Skip to content

Gate publishing on the managed source's claims - #849

Merged
rdimitrov merged 1 commit into
rdimitrov/validate-issue-843from
rdimitrov/publish-source-claims-845
Jul 17, 2026
Merged

Gate publishing on the managed source's claims#849
rdimitrov merged 1 commit into
rdimitrov/validate-issue-843from
rdimitrov/publish-source-claims-845

Conversation

@rdimitrov

Copy link
Copy Markdown
Member

What

Fixes #845: publishing into the managed source now requires the caller's JWT to cover the source's claims — not just the entry's claims.

⚠️ Stacked on #848 (base branch rdimitrov/validate-issue-843). It builds on the validateClaimsVisible* helpers introduced there. Review/merge #848 first; this will retarget to main afterward.

Why

POST /v1/entries was gated by the manageEntries role and an entry-claims ⊆ JWT check, but nothing validated the managed source's own claims (getManagedSource even discarded the Claims field). auth.md §4 already stated the intended behavior — "tag the managed source … otherwise no non-super-admin caller can publish to it" — so the code was the outlier.

The gap: entry claims are subset-validated, so a contoso writer can't create an {org:acme} entry — but they could publish an {org:contoso} entry into acme's shared managed source, squatting names in the first-come-first-served namespace. This closes that cross-tenant hole.

Change

  • getManagedSource now populates Claims (previously dropped).
  • Server + skill publish transactions add a visibility check (caller JWT must cover the source's claims — OR-within-array, auth.md §3), mirroring how resolveSourceIDsWithGate gates referencing a source.
  • An untagged managed source is now publishable only by super-admin (default-deny, §4).
  • Docs: auth.md §4/§5 updated.

Scope: publish only (deliberate)

Delete and update-claims are not changed — they already gate on the entry's own claims (validateClaimsVisibleBytes(existing.Claims)), which for a published entry is the meaningful per-entry authorization. Adding a redundant source-claims check there isn't necessary. Publish is the actual gap (no entry exists yet to gate on).

Semantics: visibility (OR), not subset (AND)

The check compares the caller against the source's existing claims, so per the #848 taxonomy it's the visibility direction (OR-within-array) — consistent with referencing a source. (The issue tentatively assumed subset/AND; visibility keeps it uniform with every other existing-claims gate.)

⚠️ Behavior change / migration note

A managed source with no claims, running with authz on, becomes super-admin-only for publishing. This is exactly what auth.md §4 prescribes (unlabeled ≠ public), but it will affect existing deployments that ran with an untagged managed source. Recovery: tag the managed source with a tenant-wide claim (e.g. {org: "acme"}) in config. This is a maintainer-facing decision — the issue explicitly flagged "fix code vs fix spec"; this PR is the "fix code" proposal.

Testing

  • New TestPublish{Server,Skill}Version_SourceClaimsGate (integration): covered / not-covered / untagged-default-deny / nil-JWT-bypass / array-OR / super-admin-bypass
  • Existing publish/delete/get/update claim tests updated (managed source now tagged {org:acme}) — all green
  • Full internal/service/db + internal/authz integration suites pass (real Postgres); go vet, gofmt, golangci-lint clean

Fixes #845

🤖 Generated with Claude Code

`POST /v1/entries` validated the entry's claims against the publisher's
JWT but never checked the managed source's own claims, so a
`manageEntries` writer could publish into a source they don't cover —
e.g. squat names in another tenant's shared managed source. `auth.md` §4
already promised the opposite ("no non-super-admin caller can publish to
it").

Populate the source's claims in `getManagedSource` (they were silently
discarded) and add a visibility check — the caller's JWT must cover the
source's claims (OR-within-array, §3) — in the server and skill publish
transactions, mirroring how referencing a source in a registry is gated.
An untagged managed source is now publishable only by super-admin
(default-deny, §4). Delete and update-claims are unchanged: they are
already gated on the entry's own claims.

Document the gate in `auth.md` §4/§5.

Fixes #845

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 62.07%. Comparing base (7032c14) to head (ac0d1ad).

Additional details and impacted files
@@                       Coverage Diff                        @@
##           rdimitrov/validate-issue-843     #849      +/-   ##
================================================================
+ Coverage                         62.03%   62.07%   +0.04%     
================================================================
  Files                               109      109              
  Lines                             10719    10724       +5     
================================================================
+ Hits                               6649     6657       +8     
+ Misses                             3484     3482       -2     
+ Partials                            586      585       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rdimitrov
rdimitrov merged commit dd8a96d into rdimitrov/validate-issue-843 Jul 17, 2026
16 checks passed
@rdimitrov
rdimitrov deleted the rdimitrov/publish-source-claims-845 branch July 17, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants