-
Notifications
You must be signed in to change notification settings - Fork 6
fix(gcp): resolve binding edge cases and improve error handling #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c486ef7
b915f0b
f2d5546
6002b5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -237,6 +237,151 @@ See the [Conditions documentation](./index#conditions) for full details and AWS | |||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ## 6. New: Binding Field on Statements | ||||||
|
|
||||||
| The `binding` field is an optional property on permission statements that declares the explicit CSP resource where a custom role should be created and where the resulting IAM binding should be applied. | ||||||
|
|
||||||
| ### Why it exists | ||||||
|
|
||||||
| Some providers create custom roles at a different scope than the request tenant. The most common case is **GCP**: custom roles can only be created at the `projects/{id}` or `organizations/{id}` level, but a request tenant may be a folder (`folders/{id}`). Without `binding`, the GCP provider would fail when asked to create a custom role for a folder tenant. | ||||||
|
|
||||||
| The field exists to resolve this explicitly and cleanly, regardless of provider. See [Binding](./index#binding) in the reference documentation for the full format per provider. | ||||||
|
|
||||||
| ### No migration required — but a deprecation warning may appear | ||||||
|
|
||||||
| If your existing roles have `permissions.allow` statements that include `targets` pointing at a specific project (e.g. `projects/my-project/...`), the GCP provider previously attempted to infer the binding project from those targets whenever the request tenant was a folder. This inference still works, but it now emits a **deprecation warning** in the agent logs: | ||||||
|
|
||||||
| ``` | ||||||
| level=warning msg="permissions.allow statements are missing 'binding'; inferring project from targets. Set an explicit 'binding' on each statement to remove this warning." | ||||||
| ``` | ||||||
|
|
||||||
| If only some statements in the role set `binding`, a different warning is emitted: | ||||||
|
|
||||||
| ``` | ||||||
| level=warning msg="some permissions.allow statements have 'binding' set but not all; the explicit binding values will be ignored and the project will be inferred from targets instead. Set 'binding' on every statement or remove it from all statements." | ||||||
| ``` | ||||||
|
|
||||||
| To silence the warning and make the intent explicit, add `binding` to the relevant statements: | ||||||
|
|
||||||
| ```yaml | ||||||
| # Before (still works, but logs a deprecation warning) | ||||||
| permissions: | ||||||
| allow: | ||||||
| - operations: | ||||||
| - "gcp-prod:secretmanager.secrets.get" | ||||||
| targets: | ||||||
| - "projects/my-project/secrets/*" | ||||||
|
|
||||||
| # After (explicit, no warning) | ||||||
| permissions: | ||||||
| allow: | ||||||
| - binding: "projects/my-project" | ||||||
| operations: | ||||||
| - "gcp-prod:secretmanager.secrets.get" | ||||||
| targets: | ||||||
| - "projects/my-project/secrets/*" | ||||||
| ``` | ||||||
|
|
||||||
| ### Validation | ||||||
|
|
||||||
| - All statements within the same role that set `binding` must agree on the same value. Conflicting values produce a configuration error. | ||||||
| - `binding: "folders/..."` is rejected by the GCP provider — folders are not a valid scope for custom role creation. | ||||||
| - `binding` does not restrict which resources the operations act on; `targets` continues to control that. | ||||||
|
||||||
| - `binding` does not restrict which resources the operations act on; `targets` continues to control that. | |
| - `binding` does not itself restrict which resources operations apply to. Conceptually, `targets` define the resource scope, but enforcement is provider-specific (for example, the GCP provider treats `targets` as metadata only and does not enforce them). |
Copilot
AI
Mar 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The doc says statement id is "not shown in notifications or user-facing messages", but the UI template internal/daemon/static/role.html now renders the ID column. Please clarify the doc (e.g. "not shown in Slack/email notifications"), or remove the claim.
| - The value is **not shown** in notifications or user-facing messages; it is an internal identifier only. | |
| - The value is primarily an internal identifier and is not included in Slack/email notifications, though it may appear in administrative UI tables. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -61,6 +61,38 @@ func GetValidator() *validator.Validate { | |||||
| // Log error but don't panic | ||||||
| } | ||||||
|
|
||||||
| // Register custom validator for strict snake_case identifiers | ||||||
| // Used by Statement.Name field — must start with a lowercase letter, | ||||||
|
||||||
| // Used by Statement.Name field — must start with a lowercase letter, | |
| // Used by Statement.ID field — must start with a lowercase letter, |
Uh oh!
There was an error while loading. Please reload this page.