feat: command caller specification#106
Conversation
There was a problem hiding this comment.
Pull request overview
Adds per-command caller allowlists so commands can restrict who may submit jobs, based on regex matching against the authenticated user (e.g., X-Heimdall-User via auth header plugin).
Changes:
- Added
allowed_callerstoCommand, compiling/caching regex patterns and exposingIsCallerAllowed. - Enforced the allowlist during job submission, rejecting disallowed callers with a dedicated error.
- Documented the new
allowed_callersconfiguration in the README.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| README.md | Documents allowed_callers and how it affects job submission. |
| pkg/object/command/command.go | Adds allowlist config field, regex compilation/cache, and caller check method. |
| internal/pkg/heimdall/job.go | Enforces allowlist in submitJob and introduces ErrCallerNotAllowed. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
245923f
| var ( | ||
| ErrCommandClusterPairNotFound = fmt.Errorf(`command-cluster pair is not found`) | ||
| ErrJobCancelFailed = fmt.Errorf(`async job unrecognized or already in final state`) | ||
| ErrCallerNotAllowed = fmt.Errorf(`caller is not allowed to run this command`) |
There was a problem hiding this comment.
Seems like its an authorization piece. Do you thin it can go in auth plugin? Maybe we can expose a new method, like AuthorizeCommandRequest() in auth plugin here which will do the job?
There was a problem hiding this comment.
This is a simple static ACL co-located with the command config. Moving it to the auth plugin would mean the auth plugin has to know about commands, every deployment would need an auth plugin just to express "user X can run command Y", even for the simplest cases.
There was a problem hiding this comment.
Hey Yash, nice work, very clean. Just one optional optimization. I think you can evaluate all the patterns in one go by joining them into a single regex before compiling:
parts = append(parts, `(?:` + raw + `)`)
// ...
regexp.Compile(`^(?:` + strings.Join(parts, `|`) + `)$`)this would get rid of the loop but its more cosmetic than anything since the actual optimization isn't huge
Description
This pull request introduces support for per-command caller allowlists, enabling commands to restrict which users can invoke them based on anchored regex patterns. The implementation includes changes to both the command object and the job submission logic, along with an update to the documentation.
Changes
Command allowlist enforcement:
AllowedCallersfield to theCommandstruct, allowing configuration of permitted callers as anchored regex patterns. Patterns are compiled and cached for efficient matching. (pkg/object/command/command.go, [1] [2]IsCallerAllowedmethod on theCommandstruct to check if a user matches any of the allowed caller patterns. (pkg/object/command/command.go, pkg/object/command/command.goR68-R102)internal/pkg/heimdall/job.go, [1] [2]Documentation:
README.mdto describe the newallowed_callersfeature and its effect on command invocation.Tests
Tested locally on docker compose and with unit tests. All passed.