Skip to content

feat: policy command family (/v1/policy + /v1/org/policy)#93

Merged
guyb1 merged 1 commit into
mainfrom
feat/policy-commands
Jul 21, 2026
Merged

feat: policy command family (/v1/policy + /v1/org/policy)#93
guyb1 merged 1 commit into
mainfrom
feat/policy-commands

Conversation

@guyb1

@guyb1 guyb1 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What

Adds the policy-engine command surface:

  • onecli policy (project scope) and onecli org policy (organization scope, admin org key): rules list|get|create|update|delete|reorder, default get|set, publish, status — 10 operations per scope against /v1/policy and /v1/org/policy.
  • Staged model built in: writes land in the scope's draft; each write auto-publishes only when the draft has no other staged changes, otherwise the publish is withheld (publishSkipped, pendingChanges in the JSON output) so a write never ships someone else's staged edits. --publish-all overrides, --no-publish always stages. status composes the staged diff client-side via a faithful Go port of the server's policy-diff library (custom rules only, keyed by logicalId).
  • Raw --json PATCH bodies: sent verbatim, so explicit JSON nulls (the only way to clear rateLimit/conditions server-side) reach the wire.
  • Error mapping: new GONE / VALIDATION_ERROR codes for 410/422; route-miss 404s upgrade to an actionable "this server does not support the (org) policy API" message; a missing-project 401/400 points at --project instead of the misleading auth login.
  • Legacy rules / org rules commands keep working against self-hosted servers that predate the policy engine; their help now points at the policy family (cloud deployments reject legacy writes with 410 Gone).

Why

OneCLI Cloud runs the policy engine; the legacy /v1/rules write surface returns 410 Gone there. The CLI needs first-class commands for the canonical API, with the staged draft→publish semantics made safe for agent use (a publish snapshots the whole scope draft, so the guard prevents accidentally enforcing other users' staged changes).

Verification

  • go build / go vet clean, golangci-lint 0 issues, go test -race -count=1 green.
  • Wire-level tests pin: payload encoding for every target kind (connectionId field), status-query routing, the reorder body, verbatim raw PATCH bodies (nulls survive), 410/422/403 envelope pass-through, route-miss 404 upgrade vs resource-404 pass-through, last-publish JSON null.
  • The diff port is golden-tested against the server's semantics (derived rows excluded, "" vs null distinct, reorder + default-change counting), plus a composition test pinning the publish guard's four GET feed.
  • Publish-guard flow covered via injected ops: withheld / clean auto-publish / --publish-all / publish-failure-after-write / contradictory flags.

Review

Reviewed via the ship pipeline: hunk-by-hunk self-review, then two independent adversarial reviewers, then a cross-repo fix-attacker pass verifying the fixes and the cross-repo contract (paths, field names, enums, status codes, logicalId semantics) against the server source. Skills applied: agent-first-cli (command surface / output contracts: 3 fixes), golang-patterns + golang-pro (raw-body handling, diff-port fidelity: 4 fixes). Findings fixed: 1 high (typed --json round-trip silently dropped JSON null clears — now raw pass-through, wire-tested), 2 medium, 6 low. Final gates green.

Related PRs

Merge order: this PR and the SDK PR are independent and can merge anytime (the API is live on OneCLI Cloud and current Enterprise releases); the docs PR merges last.

🤖 Generated with Claude Code

Adds `onecli policy` and `onecli org policy`, the staged draft-to-publish
policy engine surface (10 operations per scope): rules
list/get/create/update/delete/reorder, default get/set, publish, and
status (a client-composed staged diff via a faithful Go port of the
server's policy-diff library).

Writes auto-publish only when the scope's draft has no other staged
changes; otherwise the publish is withheld (`publishSkipped` +
`pendingChanges` in the output) so a write never ships someone else's
half-finished edits. `--publish-all` overrides the guard; `--no-publish`
always stages. `--json` PATCH payloads are sent verbatim as raw JSON so
explicit nulls (the only way to clear rateLimit/conditions server-side)
reach the wire.

The legacy `rules` / `org rules` commands keep working against
self-hosted servers that predate the policy engine and now point at the
policy family in their help text; cloud deployments reject legacy writes
with 410 Gone. New GONE and VALIDATION_ERROR error codes map 410/422
responses to actionable output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@guyb1
guyb1 merged commit 6741097 into main Jul 21, 2026
2 checks passed
@guyb1
guyb1 deleted the feat/policy-commands branch July 21, 2026 21:25
@guyb1 guyb1 mentioned this pull request Jul 21, 2026
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