Repository navigation
feat(org): let developers set their own team's app secrets - #139
Conversation
app.yaml resources.secrets are created with a PLACEHOLDER value, but the developer permission set could only read /javabin/apps/<team>/*, so no team could set its own secrets. Allow ssm:PutParameter on the team's own path, deny writes to the platform-managed Cognito credentials and auth requests, and allow ecs:UpdateService on the team's own services so tasks can be restarted to pick up new values. Used by javabin secret set in javaBin/javabin-cli. terraform/org is human-applied. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Terraform Plan🚧 Changes detected — Plan: 72 to add, 27 to change, 1 to destroy. Plan outputLLM ReviewRisk: 🔴 HIGH The plan modifies the developer permissions boundary (adding EC2 security group authorize/revoke and iam:UpdateAssumeRolePolicy to allowed actions, and changing the ECS execution role exemption), and creates many new per-team ECS execution IAM roles, all of which need security review before apply.
|
…Ctrl-C - set checks the parameter exists first and refuses to create it (the platform creates declared secrets on deploy) - remove --restart / ECS UpdateService; the platform restarts the service automatically when a secret changes (javaBin/platform#139) - restore the terminal if interrupted during the hidden prompt - document why list decrypts; update CLAUDE.md Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review feedback on #139: - PutParameter requires the parameter's team tag to match, so developers can only set secrets the platform created; creating one by hand would break the app's next terraform apply (ParameterAlreadyExists). - db-master-password joins the platform-managed deny list. - Drop ecs:UpdateService from the developer permission set: it also allows changing networking and task definitions. Instead a new javabin-app-secret-rollout Lambda forces a new deployment of {team}-{app} when one of its secrets is updated (EventBridge). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Terraform Plan🚧 Changes detected — Plan: 7 to add, 0 to change, 0 to destroy. Plan outputLLM ReviewRisk: 🟢 LOW Plan creates 7 new resources (no changes or destroys) for an EventBridge-triggered Lambda that restarts app ECS services when /javabin/apps/ SSM parameters are updated.
|
Terraform Plan🚧 Changes detected — Plan: 7 to add, 0 to change, 0 to destroy. Plan outputLLM ReviewRisk: 🟢 LOW Plan creates 7 new resources for an EventBridge-triggered Lambda (app_secret_rollout) that restarts ECS services when app secrets in Parameter Store change; no existing resources are modified or destroyed.
|
* feat(secret): set app.yaml secrets from the CLI Secrets declared in app.yaml resources.secrets are created with a PLACEHOLDER value, and developers had no way to set the real one. javabin secret list shows which still hold PLACEHOLDER (never the values); javabin secret set <name> stores a value as an SSM SecureString under /javabin/apps/<team>/<app>/, prompting without echo or reading --stdin, and --restart forces a new ECS deployment so tasks pick it up. Only names declared in app.yaml are accepted. Needs the developer permission set change in javaBin/platform (terraform/org, human-applied). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(secret): never create parameters, drop --restart, restore tty on Ctrl-C - set checks the parameter exists first and refuses to create it (the platform creates declared secrets on deploy) - remove --restart / ECS UpdateService; the platform restarts the service automatically when a secret changes (javaBin/platform#139) - restore the terminal if interrupted during the hidden prompt - document why list decrypts; update CLAUDE.md Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…en in (#145) Fixes #144. ## Why - **Verified in CloudTrail:** every Identity Center session carries `principalTags: {team: ""}` on `AssumeRoleWithSAML`, for `javabin-team-cupcake`, `javabin-team-jzwatch` and `javabin-admin` alike. - **Cause:** the ABAC mapping reads `${path:enterprise.team}`, and nothing ever sets that attribute on users. - **Effect:** the per-team permission sets attach `javabin-developer-boundary` as a policy, and its `DenyXTeam` compares each resource's `team` tag with that empty principal tag. So developers are denied everything team-scoped: their own app secrets (`javabin secret list/set`), `/ecs/<team>/*` logs, and their ECS services. ## What changed - **`terraform/platform/iam/boundary.tf`:** - The boundary JSON moves into a local. - New `javabin-team-{team}-guardrails` per registered team: the same rules with `${aws:PrincipalTag/team}` replaced by the team name. - The guardrails are tagged `team=shared`, and `DenyBndMod` now also covers `javabin-team-*-guardrails`, so team CI roles can't rewrite them. - Rendered size is 5,553 bytes, under 6,144. - **team-provisioner, for `javabin-team-{team}`:** - Attaches `javabin-team-{team}-guardrails` and detaches the shared boundary. - The inline policy now denies writes to platform-managed parameters (`cognito-client-*`, `auth`, `db-master-password`). - It also denies creating parameters that don't exist yet: an untagged parameter would break the app's next `terraform apply`. - It re-provisions the permission set so the change reaches the account. - **IAM for the provisioner:** `Detach…`, `ProvisionPermissionSet`, `DescribePermissionSetProvisioningStatus`, and `iam:GetPolicy` on the guardrail policies. - **Docs:** CLAUDE.md (known issue, naming) and app-yaml-reference (which SSO role to use for secrets). The ABAC `javabin-developer` permission set in `terraform/org` is still unable to reach team resources. That's documented rather than fixed here, because the per-team sets are what people use. #139's `terraform/org` change targets that set, so it doesn't need applying for secrets self-service. ## After merge 1. Platform CI creates the guardrail policies. 2. Run **Provision Teams** in javaBin/registry (manual run), which attaches them and re-provisions the permission sets. 3. Sign in again with `javabin-team-cupcake`, then `javabin secret list`. ## Checks - The Lambda tests pass, including a new one for attach/detach, the deny statements and reprovisioning. - `terraform validate` passes. - `terraform console` confirms the substitution renders the team name in both the conditions and the ARNs. ## Guard overrides - `aws route53 change-resource-record-sets --hosted-zone-id Z09335963LMV0Z5QB9L45 --change-batch file:///tmp/cupcake-cname-delete.json` — deleted the old `cupcake.javazone.no` CNAME (→ `d2cxhqskuuhit7.cloudfront.net`) to cut frosting over to the platform, on the user's explicit instruction. Not part of this PR's code; listed because it ran from this session. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ole plan (#147) ## Why Reviews kept saying "Plan is truncated; the remaining changes ... could not be reviewed". Where the input was actually cut: | Reviews | Cut by | Real? | |---|---|---| | #134, #135 (14:14, 14:31), #137, #138, #139 on 2026-10-23, before #141 merged at 15:43 | the old 80k cut in `review-plan.py` | yes. These include the quoted "other roles, Lambdas, or networking" review (#135, 14:31) | | #135 on 2026-10-24 09:53 (run 40083680062) | #141's 400k cap: the plan was 830k chars, 231 destroys (destroy diffs print every attribute) | yes. The model saw 28 of 231 changes and correctly said so | | #145 (2026-10-24 09:25, 09:40), #146, app reviews (cupcake#258, frosting#249/#250) | none | no truncation claims | Ruled out: - (a) The PR comment's 60k cut: the review reads `plan-output.txt` itself. The cut was silent to humans, though, so the comment now says when it is cut. - (b) `run-plan.sh` writes the full `-no-color` output with no head/tail. - (c) platform-ci reviews `terraform/platform/plan-output.txt`, the full file. - (e) No reviews hit `max_tokens`. Converse is still called without inferenceConfig (no maxTokens set, on purpose), but a `stopReason: max_tokens` answer is now discarded instead of trusted. - (f) The Lambda reads the whole S3 object. ## What changed - `scripts/review-plan.py`: no default input cap. The whole plan goes to Haiku 5.5, which has a 1M-token context. `REVIEW_MAX_PLAN_CHARS` still turns on the existing notice + change-list mode if it is set. - The prompt now opens with `COMPLETE PLAN` (change count + the `Plan:` line) and says not to call the plan truncated. It also explains that Terraform hides parts of every plan by design: `# (N unchanged attributes/blocks/elements hidden)`, `(sensitive value)`, `(known after apply)` and partial `jsonencode` diffs are not truncation. - `stopReason == "max_tokens"` → returns None. Platform CI records FAILED; the Lambda retries. - `scripts/post-plan-comment.sh`: adds a notice when the plan is cut at 60k (GitHub's comment limit) and keeps the cut-off point configurable. - Docs: `docs/ci-workflow.md`. Trade-off: a plan larger than the model's context now fails the review (FAILED, override available) instead of being cut. ## Checks - `python3 -m unittest discover -s scripts/tests`: 38 OK. New tests: the complete-plan declaration, the elision markers, no default cap (2M-char plan), an 830k destroy plan sent whole, max_tokens discarded, and the comment cut notice. - `python3 -m unittest discover -s terraform/lambda-src/tests`: 63 OK. New tests: COMPLETE PLAN reaches Bedrock, and a max_tokens answer is retried. - `terraform fmt -check -recursive terraform`: OK. `shellcheck scripts/post-plan-comment.sh`: OK. No workflow changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Why
app.yamlresources.secretsare created with the valuePLACEHOLDER, but thejavabin-developerpermission set can only read/javabin/apps/<team>/*, so no team can give its secrets real values. cupcake needsSP_USER,SP_PASSWORD,BRING_API_USERandBRING_API_KEY.What changed
terraform/org/identity-center.tf,javabin-developer(human-applied):ssm:PutParameter,LabelParameterVersionandGetParameterHistoryon/javabin/apps/${PrincipalTag/team}/*, only for parameters tagged with that team. That means only secrets the platform created; a hand-made parameter would break the app's nextterraform apply.*/cognito-client-*,*/authand*/db-master-password, which are platform-managed.javabin-app-secret-rollout(CI-applied): on an SSMUpdateunder/javabin/apps/, it forces a new deployment of{team}-{app}, because ECS reads secrets only at task start. Developers get noecs:UpdateService: that action would also let them change networking and task definitions.javabin secret list/set.Applying
terraform/orgmust be applied by hand:cd terraform/org && terraform plan && terraform apply(javabin admin). It should show one in-place update toaws_ssoadmin_permission_set_inline_policy.developer.Known limit
A session carries a single
teamtag. A hero in several teams can manage only the team their session is tagged with.Checks
test_app_secret_rollout.py.terraform validatepasses onterraform/platformandterraform/org.db-master-passworddeny, and dropping UpdateService.🤖 Generated with Claude Code