feat: add entitlements create - #112
Merged
Merged
Conversation
Collapses the resource-type/resource/entitlement sequence the
configure-new-app guide previously spelled out as three raw "c1i api"
calls into one command.
--resource-type-id and --resource-id skip whichever of the first two
POSTs the caller already has, so one resource type can carry many
resources and one resource many entitlements; without them all three
are sent. The server requires appResourceTypeId AND appResourceId on
the entitlement even though the OpenAPI schema marks only displayName
required, so --resource-id without --resource-type-id is a usage error
(exit 2) rather than a 400.
--duration-grant covers the standing-vs-time-boxed distinction inline
rather than sending readers to a raw POST for it. It takes a protobuf
duration ("3600s"); a Go-style "1h" is refused by the server.
The three writes are not atomic and nothing is rolled back, so a
failure part-way through names the objects this run created and the
flags that reuse them. --dry-run previews all three requests, standing
in NEW_APP_RESOURCE_TYPE_ID/NEW_APP_RESOURCE_ID for ids that only exist
after a real preceding step, and its banner names only the stand-ins
the preview actually uses.
The resource-type enum has one definition, resourceTypeKinds, that the
help text and flag usage are built from and that a test holds README.md
and the guide to.
Also corrects the guide, which opened by saying no such command exists,
and two of its timing claims that this session measured: entitlement
owners lag the write like app owners do (116s), and the entitlement
search index is fast but not transactional.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… advice work --owner-id "" (an unset shell variable) created an ownerless entitlement at exit 0, which an async owner read cannot tell apart from "not provisioned yet". Empty and whitespace-only owner ids are now a usage error before anything is sent; the flag is a StringArray because pflag's slice parser drops an empty value outright, so `--owner-id "" --owner-id U` never reached the check. An explicit --resource-type-display-name/--resource-display-name "" likewise fell back to --display-name and mis-named the object; both now take the same requireNonEmptyIfSet guard as the id flags. The partial-failure message advised a retry the command then rejected: the reused ids make the create-only flags of the original invocation a usage error. It now names those flags for dropping, and a test parses the message and feeds the retry back through the flag parser. Help text: only a CUSTOM resource type can repeat on one app -- a second ROLE, GROUP or VAULT 500s with "app resource type already exists", quoted so it is greppable from both directions, and reused via --resource-type-id. The exit code for it is unchanged. The opening sentence also claimed the app must be manually managed; the app need not be, only the entitlement created on it is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The partial-failure message and the CUSTOM-singleton caveat had landed in the command help, README and agents.md but not in docs guide configure-new-app, which was rewritten in this same branch. The guide quoted the pre-fix retry — one its own example command cannot produce, and the one the fix exists to stop advising — and listed all eight resource-type kinds with no hint that only CUSTOM may repeat. Two guards so neither drifts again: the singleton check now covers the guide, and a new test builds the remediation from createdSoFar and requires the docs that quote it to carry the flags-to-drop clause. The remediation test also covers the resource-create failure, where the retry must keep --resource-display-name because the object it names was never created. That path fails silently rather than loudly, and nothing pinned it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The verbatim test built the expected message and then asserted only that the docs contain the word "dropping", so renaming a flag left both docs quoting a message the code can no longer emit while the test stayed green. It now compares against the message itself, built by the real planner rather than a hand-made plan, so a regression in how the drop list is populated fails here. The singleton paragraph added in the previous commit told the reader to reuse the existing type with --resource-type-id without saying to drop --resource-type, so following it exits 2 — the same class of guide-advised retry that commit removed from this file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous commit fixed half of a two-flag rejection: reusing a type also refuses --resource-type-display-name, which the guide's own worked example passes, so following the corrected paragraph verbatim still exited 2. The other three docs carried the same incomplete advice, and the agent doc stated no exclusivity at all. The refused flags are now one list in the code, and a test holds every doc that advises the reuse to it — so adding a third flag fails until the docs say so. Prose is not a quote, which is why the verbatim guard could not see this. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous guard asserted almost nothing. "--resource-type" is a prefix of "--resource-type-id", so that half was satisfied by the id every doc already names; the other half was satisfied by unrelated text elsewhere in three of the four docs, one of it an example that PASSES the flag. It would not have caught the defect it was written for. Three heuristic versions failed the same way — matching prose, then anchoring on the instruction, which let a doc that dropped the instruction be skipped rather than failed. Each doc now carries a fixed clause per reuse pair, required verbatim, and the clause is checked against the code's own list so the docs cannot be complete against a stale contract. The retry message was still built from a hardcoded copy of the flags, so adding one would have left the message advising a retry that exits 2 while the docs looked correct. Both pairs are single lists now, read by the reject call, the message and the docs alike. --resource-id refuses --resource-display-name and no doc said so; all four now do, verified live. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The check that the clause names every refused flag used a substring match, so "--resource-type" was satisfied by "--resource-type-display-name" in the same clause — the exact prefix bug the clause design was meant to close, one layer in. A reviewer shortened the clause to name one flag, the whole suite stayed green, and the original defect came back: advice that exits 2. docMentionsFlag already exists for this, with a comment describing the trap. Using it, rather than a fourth hand-rolled matcher. Requiring the clause without backticks forced bare flag names into two markdown files that backtick everything else, and restoring correct markdown failed the build. Backticks are stripped before comparing instead. Also fails a doc that carries the clause but never names the id flag, and one that negates it. Renamed: it covers resources too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
flattenDoc was a second name for flatten, which this package already had. Deleted. The four docs that carry this command's claims were written out in full by two guards; extracted once. The other two guards keep their own sets deliberately -- the kinds check also reads the flag's usage string, and the remediation quote lives in only two docs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This branch carried its own copy of the empty-occurrence rule, written before the shared one existed. Two implementations of one rule is the drift #111 was opened to remove, and its guard rejected the direct StringArray registration here, so keeping the copy would have failed CI on main. The bespoke wording is gone with it; the three rows that asserted it now assert the shared one, which TestRepeatableStringFlagErrorHasOneWording pins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
c1i entitlements createwraps the three-call sequence — resource type,resource, entitlement — into one command. The guide already documented the raw
sequence; this makes it one call, and
--owner-idrides along in the createrequest so owners need no follow-up.
Behaviour worth knowing
objects the earlier ones created still exist. The error names them, the flags
that reuse them, and the flags the retry must drop — following it verbatim is
what makes the retry succeed, since a flag describing an object that now
exists is refused.
CUSTOMresource-type kinds repeat per app. A secondROLE,VAULTor
PROFILE_TYPEreturns a 500,app resource type already exists, whichmaps to exit 6 even though retrying never helps. Reuse the existing one with
--resource-type-id.--owner-idused to create an entitlement with no owners at exit 0 —undetectable by reading back, since owner writes are async.
--duration-granttakes a protobuf duration:3600s, not1h.Verification
Every flag and failure path exercised live, exit codes captured directly rather
than through a pipe. The ownerless-create defect reproduced before the fix and
confirmed after. The remediation loop run end to end: the original invocation
fails, the retry it prints succeeds. The reuse advice in all four docs executed
— dropping both refused flags exits 0, keeping either exits 2. Owner visibility
polled rather than read once. Test objects soft-deleted, verified by
deletedAt.--owner-iduses the shared repeatable-flag registrar from #111 rather than aprivate copy of the same rule.
🤖 Generated with Claude Code