Skip to content

sec(ci): allowlist the roles a per-secret Secret Manager grant may carry - #1213

Merged
IAmJSD merged 3 commits into
LeanerCloud:mainfrom
IAmJSD:fix/issue-505
Oct 26, 2026
Merged

IAmJSD merged 3 commits into
LeanerCloud:mainfrom
IAmJSD:fix/issue-505

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #1207. This branch starts from #1207's head (e9e1c627, which hardens the same script for #150). Please review only the commits after e9e1c627: compare e9e1c627...fix/issue-505. Until #1207 merges, the diff against main includes #1207 too. Once it merges, main will be merged into this branch (no rebase).

Root cause

scripts/check-gcp-secret-scope.sh exempts the role = "roles/secretmanager.X" line inside a per-secret IAM resource, and its pattern accepted any X (roles\/secretmanager\.[A-Za-z]+). So once a grant was per-secret, the guard never looked at which role it carried. The #504 review's mutation of admin_password_writer from secretVersionAdder to roles/secretmanager.admin exited 0.

Fix

Inside a per-secret IAM resource (google_secret_manager_{,regional_}secret_iam_{member,binding,policy}), every role = line must now be one of these two literals, matched case-sensitively since IAM role names are case-sensitive:

  • roles/secretmanager.secretAccessor
  • roles/secretmanager.secretVersionAdder

Any other role = line in such a resource is a finding with its own message. That covers a wider Secret Manager role (admin, secretVersionManager, viewer), a role from another service (roles/owner), a reference (local.x, each.value) and near-miss names (wrong case, extra suffix, trailing space). A waiver with a reason on the line above still excuses a deliberate exception, the same way it does for scope-wide grants. The change is in taint(), where #1207's agent pointed. The header, the failure guidance and the OK line are updated to match.

Why these two roles: the issue names them. They are also the only roles the repo grants per secret today: 18 google_secret_manager_secret_iam_member resources across terraform/modules/{secrets/gcp,compute/gcp/gke,compute/gcp/cloud-run,compute/gcp/cleanup-function}, 16 secretAccessor and 2 secretVersionAdder (the two admin_password_writers). iac/ has none. They match what the app calls (AccessSecretVersion, AddSecretVersion), as the issue traces.

Going beyond the issue's suggestion, on purpose: the issue suggested failing on "any other Secret Manager role". This fails on any other role at all on a per-secret resource, including ones that don't mention secretmanager. If the check only fired on secretmanager text, roles/owner on a single secret, or a role routed through a local holding roles/owner, would still pass, and both grant at least as much as secretmanager.admin. Mutation probe 4 below shows that narrower version misses 2 of the 15 lookalike lines.

Do _policy resources need the same treatment? (the issue's question)

Here is what the code actually does with this PR on top of #1207:

Per-secret _iam_policy shape Behavior
policy_data = data.google_iam_policy.x.policy_data exit 2, refused by #1207 (the type name google_iam_policy is rejected before the scan). Verified locally; no extra handling added here.
inline policy_data = jsonencode({ bindings = [{ role = "..." }] }) gets the same allowlist through this PR. Fixtures cover both the allowed case (exit 0) and admin (reported).
JSON heredoc body ("role": "roles/secretmanager.X") already reported for any Secret Manager role, because only a plain role = line is exempt (#1207's per-secret-heredoc case).
policy_data = file(...), a variable or a module output not analyzed. The roles never appear in a scanned file, and #1207's iam-policy-lookalikes fixture deliberately expects policy_data = var.secret_policy_data to exit 0. This is now listed under LIMITATIONS. None exist in the tree. Refusing that shape would reverse a #1207 decision, so I left it as a follow-up rather than doing it here.

Verification

All evidence is local fixtures and scans (the guard is a static text check, so no cloud calls are involved), on macOS with BWK /usr/bin/awk. CI runs mawk, so I also ran the suite in an ubuntu:24.04 container, where /usr/bin/awk is mawk: bash scripts/test-gcp-secret-scope.sh gives 60 passed, 0 failed, and bash scripts/check-gcp-secret-scope.sh on the real repo exits 0.

Fail before / pass after. I ran bash scripts/test-gcp-secret-scope.sh with the new tests and fixtures against #1207's guard (git show e9e1c627:scripts/check-gcp-secret-scope.sh), then against this PR's guard.

Before (e9e1c62 guard): Results: 55 passed, 5 failed.

FAIL: per-secret roles/secretmanager.admin exits 1 (#505) (expected exit 1, got 0)
FAIL: every disallowed or lookalike per-secret role is reported (#505) (exit 1; role lines: 15 22 29 36 43 50 57 64 71 78 85 92 100 108 118  ; reported: 64 71 )
FAIL: waived per-secret role outside the allowed pair exits 0 (#505) (expected exit 0, got 1)
FAIL: gke module version-adder widened to secretmanager.admin exits 1 (#505) (expected exit 1, got 0)
FAIL: per-secret role outside the allowed pair fails without its waiver (#505) (expected exit 1, got 0)

Only the .x suffix and trailing-space lookalikes were caught before. The waived case fails before because, with nothing to excuse, its waiver is reported as vacuous.

After: Results: 60 passed, 0 failed. All 7 new cases pass:

  • per-secret-allowed-roles.tf.fixture: both allowed roles in _member (one with a condition block), _binding, regional _member, regional _binding and an inline _policy. Exit 0 before and after.
  • per-secret-admin.tf.fixture: the issue's mutation. Exit 0 before, exit 1 after.
  • per-secret-role-lookalikes.tf.fixture: 15 blocks (admin, secretVersionManager, viewer, secretaccessor, SecretAccessor, secretAccessorAdmin, secretVersionAdderX, secretAccessor.x, "secretAccessor ", roles/owner, local.writer_role, plus admin or secretVersionManager on _binding, regional _member, regional _binding and inline _policy). A new run_role_lines_case helper asserts that the reported line numbers are exactly the file's role = lines, so one caught block can't hide a missed one.
  • per-secret-role-waived.tf.fixture: a waived roles/secretmanager.viewer exits 0, and the same file with the waiver stripped exits 1.
  • The real terraform/modules/compute/gcp/gke/main.tf passes as written, and a copy with its secretVersionAdder widened to roles/secretmanager.admin exits 1. This reproduces the fix(gcp/gke): grant workload SA access to the admin password secret #504 review's mutation on the real file.

Admin fixture by hand: bash scripts/check-gcp-secret-scope.sh scripts/testdata/gcp-secret-scope/per-secret-admin.tf.fixture prints OK ... and exits 0 on e9e1c62. With this PR it reports per-secret-admin.tf.fixture:9: per-secret IAM role is not roles/secretmanager.secretAccessor or roles/secretmanager.secretVersionAdder and exits 1.

The real repo still passes: bash scripts/check-gcp-secret-scope.sh gives OK: ... in 227 Terraform file(s). (exit 0).

Mutation probes on the new guard. Each mutated copy was run on the allowed and lookalike fixtures:

  1. Drop the closing "…$ anchor (prefix match): lookalike findings 11/15, so the test fails.
  2. Allow only secretAccessor: the allowed fixture exits 1, so the test fails.
  3. Match case-insensitively: 13/15, so the test fails.
  4. Run the role check only on lines containing secretmanager: 13/15 (misses roles/owner and local.writer_role), so the test fails.

Other checks:

  • shellcheck 0.11.0 on both scripts: clean.
  • git-secrets: scanned the changed script and fixtures in a fresh git init repo with an isolated HOME, using scripts/setup-git-secrets.sh and .gitallowed: clean. bash scripts/test-git-secrets-allowlist.sh: 42 PASS, 0 FAIL.
  • No trailing whitespace; every file ends with a newline; both scripts stay under 500 lines (409 and 351).
  • No Go, Terraform or workflow files changed, so the Go build/vet/lint, gocyclo, mocks guards and terraform fmt don't apply.

Out of scope / notes

  • The issue's other example, secretAccessor granted "where only a version-adder is needed", can't be caught by a static allowlist, since both roles are legitimate. That needs a per-binding intent the guard doesn't have.
  • Per-secret _iam_policy with policy_data from file(), a variable or a module output (see the table above). Possible follow-up, if wanted.

Frontend follow-up for the UI owner

None.

A maintainer, please mirror the issue's triage labels on this PR: impact/internal, triaged, priority/p3, severity/low, urgency/eventually, effort/xs, type/bug.

Closes #505

🤖 Generated with Claude Code

IAmJSD and others added 2 commits October 20, 2026 14:45
check-gcp-secret-scope.sh finds Secret Manager roles by their text, but an
authoritative google_{project,folder,organization}_iam_policy can take its
policy_data from file(), a variable with no in-tree default or a module
output, so the role it grants never appears in a scanned file and the guard
reported such configurations clean. Fail closed instead: any non-comment
mention of those types, or of data "google_iam_policy", now exits 2, as the
guard already does for the JSON encoding.

CI's terraform fmt check now covers iac/ as well as terraform/, so every
root the guard scans is held to the layout its block tracking was written
for. The self-test reads SCAN_ROOTS and fails if a root has no fmt step.

Closes LeanerCloud#150

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
check-gcp-secret-scope.sh exempted a per-secret binding's `role =` line for
any roles/secretmanager.* name, so widening a per-secret grant to
roles/secretmanager.admin (the LeanerCloud#504 review's mutation) still exited 0. Inside
a per-secret IAM resource every `role =` line must now name
roles/secretmanager.secretAccessor or roles/secretmanager.secretVersionAdder
as a literal, matched case-sensitively. Any other role there, including one
from another service such as roles/owner or a reference the guard cannot
resolve, is a finding unless waived with a reason. Those two are the only
roles the repo grants per secret and the only ones the issue names.

Inline policy_data role lines on a per-secret _iam_policy get the same check.
One built from data "google_iam_policy" already exits 2 after LeanerCloud#150; one fed
from file() or a variable remains out of reach and is listed under
LIMITATIONS.

Closes LeanerCloud#505

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 6 billable files and costs up to $1.50.

Or wait 59 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between a9b7eb8 and e562c56.

Files selected for processing: 6
  • scripts/check-gcp-secret-scope.sh
  • scripts/test-gcp-secret-scope.sh
  • scripts/testdata/gcp-secret-scope/per-secret-admin.tf.fixture
  • scripts/testdata/gcp-secret-scope/per-secret-allowed-roles.tf.fixture
  • scripts/testdata/gcp-secret-scope/per-secret-role-lookalikes.tf.fixture
  • scripts/testdata/gcp-secret-scope/per-secret-role-waived.tf.fixture
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@IAmJSD IAmJSD added impact/internal Team-internal only triaged Item has been triaged priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/eventually No deadline effort/xs Trivial / one-liner type/bug Defect labels Oct 20, 2026
@cristim

cristim commented Oct 21, 2026

Copy link
Copy Markdown
Member

Independent review 2 (claude-fleet, cold): APPROVE 5edd456

Scope: this PR is stacked on #1207. As the body asks, I reviewed this PR's own commit, e9e1c62..5edd456 (the guard's taint(), the test harness and 4 fixtures).

Findings (none blocking):

  • [non-blocking, test gap] scripts/test-gcp-secret-scope.sh (the ci(gcp): secret scope guard does not check the role on secret-level Secret Manager grants #505 cases) - Nothing pins the trailing [[:space:]]*$ anchor after the closing quote in the allowlist regex (taint() in check-gcp-secret-scope.sh).
    • With the anchor removed (M3), all 60 tests still pass.
    • That version would accept role = "roles/secretmanager.secretAccessor" != "" ? "roles/owner" : "", which evaluates to roles/owner. The head guard does report that line; I checked.
    • Fix: add one lookalike block with content after the closing quote, such as a trailing comment or a conditional.
  • [non-blocking] The PR body's probe 1 drops the closing quote and the anchor together, so it does not show that the $ alone is tested.

Against #505: this fixes the root cause.

  • Inside a per-secret resource, the old exemption accepted any roles/secretmanager.[A-Za-z]+.
  • It now requires the two literal roles, and any other role = line is a finding.
  • The real repo grants only those two roles on origin/main (16 secretAccessor, 2 secretVersionAdder), so the real scan stays at exit 0.

Attacked:

  • Mutations on a copy of the head guard, each restored and confirmed identical with cmp:
    • M1, the allowed && gate dropped: 4+ tests FAIL.
    • M2, admin added to the alternation: 3 FAIL.
    • M3, the end anchor after the closing quote dropped: 60/60 pass. Survived (the gap above).
    • M4, the role check run only when the line contains "secretmanager": the lookalikes test FAILS (it misses lines 78 and 85).
    • M5, [sS]ecretAccessor: the lookalikes test FAILS (it misses line 43).
  • Edge cases:
    • role = each.value with for_each is reported.
    • A conditional expression on the role line is reported.
    • A one-line resource with several attributes is not valid HCL, so it was dismissed.
  • Blast radius: taint() is used only inside the guard's awk. Non-secret role = lines (for example project_iam_member) are unaffected, because the check is gated on allowed, as M1 shows.

Verified locally:

  • Head, BWK awk:
    • bash scripts/test-gcp-secret-scope.sh: 60 passed, 0 failed.
    • bash scripts/check-gcp-secret-scope.sh: OK on 227 files, exit 0.
  • Head, mawk 1.3.4 (awk shimmed via PATH, matching CI): 60/0, and the real scan exits 0.
  • Static checks: shellcheck on both scripts is clean.
  • Fail-before: the head tests and fixtures against e9e1c62's guard give 55 passed and 5 failed. The 5 failures are exactly the ci(gcp): secret scope guard does not check the role on secret-level Secret Manager grants #505 cases the PR claims.
  • Merged tree: 60/0 under BWK and under mawk, and the real scan exits 0.
  • No Go or Terraform changed in this commit.

Reviewed by an independent agent with no author context (second reviewer). Review only: nothing was pushed, and the GitHub review state is unchanged.

@cristim

cristim commented Oct 25, 2026

Copy link
Copy Markdown
Member

VERDICT: APPROVE 5edd456

Independent adversarial review of #1213 at 5edd456. The PR is stacked on #1207 (still OPEN, head e9e1c62, an ancestor of this head). This verdict covers the delta e9e1c62..5edd456 (commit 5edd456, six files). #1207's commit is in the diff against main, but it is reviewed under #1207 and this verdict does not cover it. Merging main into this branch after #1207 lands changes the head and restarts the gate.

The PR fixes #505 as asked. Inside a per-secret IAM resource, scripts/check-gcp-secret-scope.sh:268-273 now requires every role = line to be exactly "roles/secretmanager.secretAccessor" or "roles/secretmanager.secretVersionAdder", matched case-sensitively and anchored at both ends. The #504 mutation (admin_password_writer widened to roles/secretmanager.admin) now exits 1, and the real tree still exits 0 (227 files).

Findings (none blocking):

  • nit scripts/test-gcp-secret-scope.sh:218-219 (per-secret-role-lookalikes fixture) - no fixture puts anything after an allowed literal on the role line. Deleting the trailing [[:space:]]*$ from the allowlist regex (check-gcp-secret-scope.sh:269) leaves all 60 tests green. Under that mutation, role = "roles/secretmanager.secretAccessor" != "" ? "roles/owner" : "" would be exempt. The shipped code reports this shape (verified below), so only the test is missing. Adding this shape as one more block in the lookalikes fixture would pin the anchor.
  • nit (PR body) - the "Mutation probes" section says dropping the anchor drops lookalike findings to 11/15. Removing only the anchor after the closing quote does not reproduce that result (see the nit above), so that probe must have changed more than the anchor.

Attacked:

  • bash scripts/test-gcp-secret-scope.sh in a scratch export of the head (macOS BWK awk): 60 passed, 0 failed. bash scripts/check-gcp-secret-scope.sh on the real tree: OK, exit 0. Not re-run under mawk here.
  • Hand-written probes against the shipped guard:
    • role = "roles/owner" on _member: exit 1.
    • Inline single-line jsonencode _policy binding carrying secretmanager.admin: exit 1.
    • A conditional expression whose first token is the allowed literal: exit 1.
  • Mutation probes on check-gcp-secret-scope.sh, each reverted:
    1. Restore the pre-ci(gcp): secret scope guard does not check the role on secret-level Secret Manager grants #505 [A-Za-z]+ role pattern: 5 tests FAIL (admin fixture, lookalikes, waiver pair, real gke module widened).
    2. Apply the role check only to lines mentioning secretmanager: the lookalikes test FAILS (misses roles/owner and local.writer_role).
    3. Drop only the trailing [[:space:]]*$ anchor: SURVIVES (nit above).
    4. Ignore waivers for the new per-secret finding: the waived-fixture test FAILS.
  • Waiver handling: the new finding reuses the existing pending-waiver path unchanged, and a waiver with nothing to excuse is still reported.
  • Blast radius: the guard runs only in CI. No Terraform, Go or workflow files change. The real gke module's secretVersionAdder grant and all 16 secretAccessor grants still pass.

@IAmJSD

IAmJSD commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE 5edd45650fec283ea8ee3b9475b5e31263d1b84a

Blocking:

  • none

Non-blocking:

Attacked:

Body-stale:

  • "This fails on any other role at all on a per-secret resource, including ones that don't mention secretmanager" and the table row "inline policy_data = jsonencode(...) gets the same allowlist through this PR" are both too broad. They hold only when each role = is on its own line. A single-line binding object, or a JSON heredoc carrying roles/owner, passes (see Non-blocking).

Reviewer: rA2. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths.

@cristim

cristim commented Oct 25, 2026

Copy link
Copy Markdown
Member

@IAmJSD this branch now conflicts with main: #1207, which it was stacked on, was squash-merged as cc132fb. Please rebase this PR's own commits onto main (git rebase --onto origin/main <old #1207 head>). If the rebased diff matches the reviewed one, both approvals at 5edd456 carry over to a delta check.

LeanerCloud#1207, which this branch was stacked on, merged as squash cc132fb.
Its content for scripts/check-gcp-secret-scope.sh and
scripts/test-gcp-secret-scope.sh is byte-identical to this branch's copy
of LeanerCloud#1207 (e9e1c62), so the conflicts are only this branch's own
additions on top: kept this branch's side for both files. The diff
against main is now exactly this PR's own change. Self-test 60/0; the
guard passes on the tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Merged origin/main (now e562c56e). #1207 merged as squash cc132fbb, byte-identical to this branch's copy of it for both conflicted scripts, so I kept this branch's side and the diff against main is now only this PR's own change. Self-test 60 passed, 0 failed; the guard passes on the tree; secrets scan clean. Needs a fresh review at this head.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE e562c56e57f4ef72080f5548caf93aed8c60ae04

Blocking:

  • none

Non-blocking:

  • scripts/check-gcp-secret-scope.sh:268 (taint): the allowlist only applies to unquoted role = lines. In an inline _iam_policy jsonencode({ bindings = [{ "role" = "roles/owner", ... }] }), a quoted HCL key is valid, and a role that doesn't mention secretmanager is not reported. I checked this with a probe file: it exits 0. The same applies to a JSON-heredoc "role": "roles/owner". None exist in the tree and the PR's LIMITATIONS covers non-inline policy_data. A one-line follow-up would accept an optional quote around role and : as well as =.

  • A trailing comment on an allowed role line (role = "roles/secretmanager.secretAccessor" # why) is now reported as a disallowed role. That's a false positive, but it fails closed and matches the guard's "trailing comments are not exempt" rule. The failure message could mention it.

  • From an earlier review (rA2), confirmed on this head, which only adds a main merge: a one-line binding object bindings = [{ role = "roles/owner", members = [...] }] inside an inline per-secret _iam_policy also exits 0, because the line doesn't start with role =. The body's "fails on any other role at all on a per-secret resource" is only true when each role is on its own line.

  • From an earlier review, also confirmed: no fixture pins the trailing [[:space:]]*$ anchor (nothing follows an allowed literal on a role line). Removing the anchor would leave the suite green, although the shipped guard does report such lines. A lookalike block with a trailing conditional would pin it.

Attacked:

  • Fail-before: I put origin/main's check-gcp-secret-scope.sh (that is, sec(ci): refuse authoritative GCP IAM policies in the secret scope guard #1207's guard) in place under the PR's tests. bash scripts/test-gcp-secret-scope.sh gave 55 passed, 5 failed: admin exits 0, only lookalike lines 64 and 71 reported, the gke widen-to-admin mutation exits 0, and both waiver cases fail. With the PR's guard it gives 60/0 under gawk and under mawk (CI's awk, forced via PATH). The real tree passes under both (OK ... 227 files).
  • Checked the taint logic by hand: the per-secret role check now runs before the secretmanager text check, so roles/owner and local.x on a per-secret resource are findings, and the anchored "…"[[:space:]]*$ rejects suffix, case and trailing-space variants. run_role_lines_case asserts the exact reported line set, so one caught block can't mask a missed one.
  • CI already runs both the guard and the self-test suite in the gcp-secret-scope job. shellcheck is clean on both scripts. secrets-scan.sh printed "clean; planted key flagged". GitHub reports MERGEABLE/CLEAN, closing [505]. All points from ci(gcp): secret scope guard does not check the role on secret-level Secret Manager grants #505 are met, plus the _policy question is answered.

Body-stale:

Reviewer: rB25. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE e562c56e57f4ef72080f5548caf93aed8c60ae04

Blocking:

  • none

Non-blocking:

  • scripts/check-gcp-secret-scope.sh:268 (taint()): the allowlist only fires on role =. Inside an inline per-secret _iam_policy jsonencode({...}), HCL also accepts role : "..." and a quoted key "role" = "...". With those spellings a non-Secret-Manager role gets through. I probed a per-secret _iam_policy whose bindings were role : "roles/owner" and "role" = "roles/editor", and the guard printed OK and exited 0. Secret Manager roles in those spellings are still caught, by the generic secretmanager branch, with the message "outside a per-secret IAM resource", which is misleading. So ci(gcp): secret scope guard does not check the role on secret-level Secret Manager grants #505 as filed is met, but the body's wider claim ("fails on any other role at all on a per-secret resource") has this gap. Suggested fix: match ^[[:space:]]*"?role"?[[:space:]]*[=:]. Not blocking: it needs a deliberately unusual spelling, and it's beyond what the issue asked for.

Attacked:

  • Read the new taint() branch. Checked that a multi-line role = (\n "roles/owner"\n) fails closed (line 8 reported), that trailing whitespace after an allowed literal still passes, and that references, near-miss case and suffix lookalikes are reported. Tried the : and quoted-key HCL object spellings above.
  • Fail-before: put origin/main's check-gcp-secret-scope.sh under the PR's suite. Result: 55 passed, 5 failed (the admin mutation, lookalike line set, waiver, gke widening, waiver-stripped). Restored, it's 60/0.
  • Ran bash scripts/test-gcp-secret-scope.sh: 60/0 on gawk 5.2.1 and 60/0 in ubuntu:24.04 (mawk, as CI uses). bash scripts/check-gcp-secret-scope.sh on the real tree exits 0 (228 files). shellcheck is clean on both scripts. No Go, Terraform or workflow changes.

Body-stale:

Reviewer: rB26. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths.

@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Local verification at e562c56e57f4ef72080f5548caf93aed8c60ae04 merged onto main (99f0b614), together with #1144, #1210, #1213, #1220 in that order (combined tree 3c7f65ac, Linux, Go 1.26.10): go build ./..., go vet with and without -tags integration, the full go test -race -short -count=1 ./..., and go test -race -tags integration -count=1 on every changed package, against Docker Postgres. All pass. CI Success and pre-commit are green on this head, with 2 approving independent review(s) on it. Nothing was run against any cloud.

@IAmJSD
IAmJSD marked this pull request as ready for review October 26, 2026 01:34
@IAmJSD
IAmJSD merged commit 9fab3a7 into LeanerCloud:main Oct 26, 2026
38 checks passed
@IAmJSD

IAmJSD commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator Author

Merged by IAmJSD's agent at IAmJSD's request (IAmJSD is acting owner while the maintainers are away), under the bar IAmJSD set: 2 approving independent review(s) on e562c56e (two required: money, auth or security path), green CI, and the combined-tree verification above. Squash-merged at exactly e562c56e57f4ef72080f5548caf93aed8c60ae04.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/xs Trivial / one-liner impact/internal Team-internal only priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/bug Defect urgency/eventually No deadline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci(gcp): secret scope guard does not check the role on secret-level Secret Manager grants

2 participants