Skip to content

Move janitor's policies routes onto HttpApi - #134

Merged
tim-smart merged 4 commits into
mainfrom
agent/nelson/30c4809acbe6
Oct 20, 2026
Merged

tim-smart merged 4 commits into
mainfrom
agent/nelson/30c4809acbe6

Conversation

@tim-smart

Copy link
Copy Markdown
Contributor

Moves the policies group onto HttpApi: list, get, listVersions, create, update, publish, delete and validate. This is the first of the four Labeling PRs, so it also renames the raw Ingress/Rules.ts to Ingress/LabelingRoutes.ts (and its test to LabelingRoutes.test.ts). The rules group needs the Rules.ts name.

  • Domain: Api/Policies.ts defines the group, and JanitorApi adds it. Labeling/Policy/Configuration.ts gains PolicyNotFound (404), PolicyConflict { current } (409), PolicyNameTaken { name } (409), PolicyInUse { policyId, rules, references } (409), PolicyHistoryRetained { policyId } (409) and PolicyInvalid { diagnostic } (422). Each endpoint declares only the errors it can fail with. create answers 201 and delete answers 204, as before.
  • Cluster: Ingress/Policies.ts is one HttpApiBuilder.group layer, merged in Routes.ts behind the API middleware.
    • The Policies service fails with the domain classes directly, typed per method. PoliciesError is gone: SQL, decode and configuration failures die.
    • The retained-history delete block is now PolicyHistoryRetained (409). It used to be a 422 PolicyInvalid.
    • withRepositoryMutation fails a disconnected repository with RepositoryBlocked { reason: "disconnected" } and lets SQL failures die. The rules service shares it.
  • Temporary glue in LabelingRoutes.ts: the policy routes and their tags leave handledTags, the Handled union and respond. RepositoryBlocked joins them and answers 409 with the tagged body. A rule write to a disconnected repository used to be a 503.
  • Web: the policy editor (validate, save, save-and-publish) and the workspace (load a policy, delete a policy) call api.policies.*. They map each tag to their own copy with catchTag/catchTags, and a fallback covers everything else.
    • The editor's free-JSON draft is decoded into the domain ProgramSource before it's sent. A draft that doesn't decode gets "The draft isn't in the policy format." instead of a server 400.
    • Rule deletion keeps the raw DeleteSubject until the rules group moves.
    • labeling-wire.ts loses its copies of PolicyDetail, PolicyVersionRecord, ValidatePolicyResponse and Manifest, and the policy endpoint paths.
  • Tests: the first commit asserts the target contract: Ingress/Policies.test.ts on makeClient, and the service tests reading diagnostic, PolicyHistoryRetained and RepositoryBlocked. The second commit makes only mechanical test changes:
    • The renamed raw-route test and its importers point at LabelingRoutes.
    • GroupsApi.test.ts saves its invalid draft through the service, because the raw PUT /policies/:id is gone.
    • The web fixtures use branded ids and the draft's caseSensitive: false default, because foldkit validates message payloads against the domain PolicyDetail.

vp check reports 0 errors, and vp test passes all 130 files and 817 tests.

Closes EFF-2520

Tests only: a new Ingress/Policies test calls the policies group through
makeClient. It covers list, get, listVersions and validate, writes made
as the Access identity, and each endpoint's refusals by tag and fields:
RepositoryNotFound, RepositoryBlocked on writes, PolicyNotFound,
PolicyConflict, PolicyNameTaken, PolicyInvalid { diagnostic }, PolicyInUse
and PolicyHistoryRetained on delete. The policy cases leave the raw Rules
test, which keeps an unused Policies for the rule-test route.

The Policies service tests read PolicyInvalid.diagnostic, expect
PolicyHistoryRetained for the retained-history delete block, and expect
RepositoryBlocked "disconnected" for a write to a disconnected repository.
Ownership reads diagnostic too.

They fail until the policies group and the domain errors land.
The policies group (list, get, listVersions, create, update, publish,
delete and validate) joins JanitorApi, and the cluster serves it through
HttpApiBuilder behind the API middleware. The raw Ingress/Rules.ts and
its test become LabelingRoutes, freeing the name for the rules group.

PolicyNotFound, PolicyConflict, PolicyNameTaken, PolicyInUse,
PolicyHistoryRetained and PolicyInvalid { diagnostic } move into
Labeling/Policy/Configuration as tagged errors with their statuses. The
retained-history delete block is PolicyHistoryRetained (409, was a 422
PolicyInvalid). PoliciesError goes: SQL, decode and configuration
failures die. withRepositoryMutation fails a disconnected repository with
RepositoryBlocked "disconnected" and lets SQL failures die, so the raw
rule routes now answer that with a 409 RepositoryBlocked body instead of a
503.

The web policy editor and workspace call api.policies.* and own the copy
for each tag. Drafts decode into the domain ProgramSource before they are
sent. The labeling-wire copies of PolicyDetail, PolicyVersionRecord,
ValidatePolicyResponse, Manifest and the policy endpoint paths go.

Test updates are mechanical: the raw-route tests import LabelingRoutes,
GroupsApi saves its invalid draft through the service, and web fixtures
use branded ids and the draft's caseSensitive default.
Tests only: the Policies service test creates a policy under a repository
janitor doesn't know and expects RepositoryNotFound, ahead of the
disconnected case it shares a test with. Today withRepositoryMutation
reads a missing row as disconnected, so this fails with RepositoryBlocked.
@tim-smart
tim-smart merged commit 57d4aa0 into main Oct 20, 2026
4 checks passed
@tim-smart
tim-smart deleted the agent/nelson/30c4809acbe6 branch October 20, 2026 04:06
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.

1 participant