honker: PRD 1.8 draft r4: Mos's rulings on duckworth-0057 (mos-1129, sage-1538): B1 in Duckworth's text, B2 his second option (only an Approve creates a grant, a hand-written grant makes nothing, row 210's hand grants a test path until #436a, the hand path out), N1 the target or its enrolled identity, N2 a revoke during creation leaves nothing usable, N3 old or field-less credential.mint makes nothing, N4 one credential.mint decision that shows the account name, N5 the arbiter route for host.sudo, N6 messaging lists and role contracts, C1 account.create as in 1.7; the B7 residual and the root-command change named for Jason
This commit is contained in:
@@ -10,12 +10,24 @@ the PRD file, this draft's anchors name 1.7's sections.
|
||||
Revision 2 makes Mos's edits a to f (mos-1124, through Sage, sage-1534) and fixes Duckworth's B1 and B2
|
||||
with notes N1 to N6 (duckworth-0057) on r1 at 3c30f1036. Revision 3 fixes Duckworth's C1 and takes
|
||||
notes N1 and N2 (duckworth-0058) on r2 at 60f5ca8fa, with Gizmoduck's enrollment wording
|
||||
(gizmoduck-0067).
|
||||
(gizmoduck-0067). Revision 4 makes Mos's rulings on duckworth-0057 (mos-1129, through Sage, sage-1538)
|
||||
on r3 at d16ccdb91: only an Approve creates a grant, one decision for a grant that makes an account, and
|
||||
the arbiter route for `host.sudo`.
|
||||
|
||||
For Jason at approval: "The main agent or chief of staff" in Q10 is read as one role under two names,
|
||||
the chief of staff. So only the chief raises a grant request, and your assistant passes your own request
|
||||
to the chief. That reading is Mos's (mos-1124). To change it, say so when you approve, and REQ-GRANT-1 changes
|
||||
before the text goes into the PRD.
|
||||
to the chief. That reading is Mos's (mos-1124). To change it, say so when you approve, and REQ-GRANT-1
|
||||
changes before the text goes into the PRD.
|
||||
|
||||
Also for Jason at approval:
|
||||
|
||||
- Only an Approve creates a grant. A grant written into the business file by hand makes nothing. An agent
|
||||
that runs as the same OS user as the stack can still write the stack's own store. That is the B7
|
||||
residual (Q182 on dragon-lin, #423 on .53 and .54), and this version doesn't close it.
|
||||
- Who decides a root command on another host changes. Once `host.sudo` is routed, a raise for it that
|
||||
cites the spec and isn't within-role goes to the arbiter for its domain, as version 1.7 set for
|
||||
`git.push.remote`, not to you. The grant and its allowlist still limit the command. In manual mode the
|
||||
decision comes to you (REQ-TRUST-2).
|
||||
|
||||
## What it changes
|
||||
|
||||
@@ -45,29 +57,31 @@ This version adds:
|
||||
|
||||
The hard waits stay with the user (Mos, mos-1117): spending money, deleting data, new external accounts,
|
||||
messages outside the fleet and the rest of REQ-WAIT-1. Approving a grant is the user resolving one of
|
||||
those hard waits, `credential.mint` and, when the grant makes an account, `account.create`. A seat's own
|
||||
Gitea user (Q190) is such an account. So no hard wait moves to an agent.
|
||||
those hard waits, `credential.mint`. A grant that makes an account, such as a seat's own Gitea user
|
||||
(Q190), is the same one decision: its method says it makes an account, and the inbox shows the account
|
||||
name before Approve. So no hard wait moves to an agent.
|
||||
|
||||
When this version lands, reviewed commits:
|
||||
|
||||
1. add the manual-mode list to the organization file schema, written only on the human's path
|
||||
(REQ-TRUST-2), and make the broker classify a listed action as needing a decision for each use, before
|
||||
any other routing.
|
||||
2. add the grant request: a decision the chief of staff raises with action `credential.mint`, or
|
||||
`account.create` when the grant makes an account, naming the agent, the method and target, and the
|
||||
exact rights (REQ-GRANT-1). The broker refuses a `credential.mint` raise, and an `account.create`
|
||||
raise that carries a grant method, from any other role. An `account.create` raise with no grant
|
||||
method, such as a PM's sign-up for a service, routes as it does in version 1.7.
|
||||
2. add the grant request: a decision the chief of staff raises with action `credential.mint`, naming the
|
||||
agent, the method and target, the exact rights and, when the method makes an account, the account
|
||||
name (REQ-GRANT-1). The broker refuses a `credential.mint` raise from any other role. An
|
||||
`account.create` raise isn't a grant request and routes as it does in version 1.7, such as a PM's
|
||||
sign-up for a service.
|
||||
3. add the grant code that runs on a resolved Approve, one method at a time, and the grant record it
|
||||
writes (REQ-GRANT-2, Vikunja #435 and #436).
|
||||
4. add the user's token store, written from the WebUI (or the CLI until the Console knows the signed-in
|
||||
human) and read only by the grant code (REQ-GRANT-3).
|
||||
5. move `host.sudo` into both `ROUTED` lists, as row 199 does for `git.push.remote`, and route it under
|
||||
REQ-CRED-4. Which definitions list it within-role is a separate reviewed role commit in `roles/`.
|
||||
REQ-CRED-4, with the arbiter route version 1.7 set for `git.push.remote`. Which definitions list it
|
||||
within-role is a separate reviewed role commit in `roles/`.
|
||||
6. update the role contracts that list the hard waits: `roles/chief-of-staff.md:75` raises grant
|
||||
requests with the REQ-GRANT-1 fields, and `roles/pm.md:55` asks the chief of staff for a grant instead
|
||||
of raising `credential.mint` itself (line numbers on origin/refactor). Other roles that list the hard
|
||||
waits get the same line as the PM.
|
||||
waits get the same line as the PM. A role's messaging list carries the chain of command.
|
||||
|
||||
## Text for the PRD
|
||||
|
||||
@@ -146,15 +160,17 @@ Under "Credentials", after REQ-CRED-3 (version 1.7):
|
||||
> rotate-by or expiry date. The chief raises one only for an agent whose reviewed role definition
|
||||
> allows that kind of credential, and the broker refuses any other. A grant can't name a wildcard, a
|
||||
> shell or an empty command. The request is a decision with the action `credential.mint`, so it goes
|
||||
> to the user as a hard wait (REQ-WAIT-1). A request that makes an account, such as a seat's own Gitea
|
||||
> user (Q190), is raised with the action `account.create` and names the credential it makes as well.
|
||||
> Both actions are hard waits, so the request goes to the user either way, and the user's one
|
||||
> resolution covers the account and its credential. So the hard-waits list doesn't change. The broker
|
||||
> checks that the chief of staff raised the request. The chain of command before that is in the role
|
||||
> contracts, not a broker check.
|
||||
> to the user as a hard wait (REQ-WAIT-1). A grant whose method makes an account, such as a seat's own
|
||||
> Gitea user (Q190), is the same one decision: the method in the grant says it makes an account, the
|
||||
> request names the account, and the inbox shows the account name before Approve. The user's one
|
||||
> resolution covers the account and its credential, so the hard-waits list doesn't change. An
|
||||
> `account.create` raise isn't a grant request and routes as version 1.7 has it. The broker checks
|
||||
> only that the chief of staff raised the request. The chain of command before that is in the
|
||||
> messaging lists and the role contracts, not a broker check.
|
||||
> - **REQ-GRANT-2.** The user approves or denies each grant request in the inbox. Approve is the only thing
|
||||
> that makes the grant code create a grant. No agent creates a grant. The user creates one by Approve,
|
||||
> or by writing it in their own business file on the human's path, as row 210 does. On Approve,
|
||||
> that creates a grant, and the code uses a grant only when it has a matching Approve record. No agent
|
||||
> creates a grant. A grant written into the business file by hand makes nothing. Row 210's hand-written
|
||||
> grants stay a test path until Vikunja #436a moves `host.run` to grants made by Approve. On Approve,
|
||||
> protected stack code does every step, not an agent and not the user: it records the grant, makes the
|
||||
> key or token, installs it on the machine or creates it on the service, and logs each step. On Deny
|
||||
> nothing is made, and the denial is logged. The grant methods are:
|
||||
@@ -167,17 +183,14 @@ Under "Credentials", after REQ-CRED-3 (version 1.7):
|
||||
>
|
||||
> The Gitea and GitHub rights units come in a later design that Jason approves.
|
||||
>
|
||||
> The approval binds the exact rights the user saw and the target's enrolled identity. A change to the
|
||||
> agent, its definition, the target, the target's identity or the rights after the raise voids it. An
|
||||
> The approval binds the exact rights the user saw and the target or its enrolled identity. A change to
|
||||
> the agent, its definition, the target, the target's identity or the rights after the raise voids it. An
|
||||
> approval is used once. A grant the code couldn't finish is undone at once on the stack's side, so it
|
||||
> is never used. What it left on the host or service stays visible as pending until it is removed, as
|
||||
> for a revoke (REQ-GRANT-4). A new grant needs a new approval, never an automatic retry. The grant
|
||||
> code runs only on a request the user resolved. A request resolved by an arbiter, the tester or any
|
||||
> agent makes nothing. The grant code makes nothing from a `credential.mint` decision raised before
|
||||
> version 1.8 or without the fields of REQ-GRANT-1, or from an `account.create` decision with no grant
|
||||
> method. An `account.create` decision with no grant method isn't a grant request and stays as version
|
||||
> 1.7 has it. A grant the user writes by hand is held to the same bounds when it is loaded: a wildcard,
|
||||
> a shell, an empty command or a missing rotate-by date is refused (REQ-CRED-4). Until the Console
|
||||
> agent makes nothing. A `credential.mint` decision raised before version 1.8, or without the fields of
|
||||
> REQ-GRANT-1, makes nothing when it is approved. Until the Console
|
||||
> knows the signed-in human (Vikunja #412), Approve is `mosaic decide` in the CLI (REQ-DEC-3).
|
||||
> - **REQ-GRANT-3.** The user enters their own personal access tokens and API tokens in the WebUI, or the
|
||||
> CLI. Only the grant code reads them, to make grants. No agent ever sees a token value or a key's
|
||||
@@ -188,14 +201,13 @@ Under "Credentials", after REQ-CRED-3 (version 1.7):
|
||||
> organization, or by the tester on a dev instance (Q173). A revoke needs no decision and no new trust.
|
||||
> It takes effect at once on the stack's side, without waiting on the network, so the next use is
|
||||
> refused. Removing the key or token at the host or service follows. Until that removal is done it stays
|
||||
> visible as pending. A revoke while the grant is being made stops it, and what was made is handled the
|
||||
> same way. Every revoke is logged with who made it.
|
||||
> visible as pending. A revoke while the grant is being made stops it, and nothing it made stays usable.
|
||||
> Every revoke is logged with who made it.
|
||||
|
||||
REQ-CRED-1, appended:
|
||||
|
||||
> Since version 1.8, a token or key for a grant is made by the grant code on the user's Approve
|
||||
> (REQ-GRANT-2). A grant the user writes in their own business file, with its key made by hand, stays
|
||||
> allowed. Tokens that exist stay as they are.
|
||||
> (REQ-GRANT-2), not by hand. Tokens that exist stay as they are.
|
||||
|
||||
REQ-WAIT-3, appended:
|
||||
|
||||
@@ -217,8 +229,8 @@ Under "Risks and open questions", a new bullet:
|
||||
- The hard waits stay with the user (mos-1117). REQ-GRANT-1 makes the grant request a `credential.mint`
|
||||
decision, already a hard wait under REQ-WAIT-1, so Approve is the user resolving it. REQ-WAIT-2 stands:
|
||||
no role file grants `credential.mint`. The grant code acts on the user's resolution, not on a role
|
||||
grant. A grant that makes an account, such as a seat's Gitea user under Q190, is also `account.create`,
|
||||
already a hard wait. So 1.8 doesn't change the hard-waits list (mos-1124 a).
|
||||
grant. A grant that makes an account, such as a seat's Gitea user under Q190, is the same one
|
||||
`credential.mint` decision. So 1.8 doesn't change the hard-waits list (mos-1124 a, mos-1129 N4).
|
||||
- Manual mode: Sage asked who sets it, where it lives and what it changes. Mos accepted these choices
|
||||
(mos-1124 b), and Jason can change them: a list of actions in the organization file, empty by
|
||||
default, changed only by the user, outside the chief's organization writes. A list rather than one
|
||||
@@ -233,37 +245,44 @@ Under "Risks and open questions", a new bullet:
|
||||
is at once on the stack's side with the host or service removal visible until done, every grant has a
|
||||
rotate-by or expiry date, and the host identity comes from the host side. Duckworth hasn't reviewed
|
||||
their draft yet, so a change there may need a change here.
|
||||
- B2 (duckworth-0057): REQ-GRANT-2 lets the user create a grant by Approve or by writing it in their own
|
||||
business file. The other choice, existing grants stay and every new one needs an Approve record, would
|
||||
leave no way to make a new grant between row 210 landing and the grant code (#435, #436) landing. Q188
|
||||
calls requiring the user to do the steps a no-fly. This text allows the hand path and requires it
|
||||
nowhere. Mos or Jason can close it once the grant code is live.
|
||||
- C1 (duckworth-0058): `account.create` is the hard wait for any new external account, not only a grant
|
||||
(REQ-WAIT-1, `vocabulary.mjs:43-46`, `roles/pm.md:55`). So landing step 2 and REQ-GRANT-2 apply the
|
||||
chief-only raise and the "makes nothing" rule only to an `account.create` raise that carries a grant
|
||||
method. A PM's sign-up for a service routes as in version 1.7.
|
||||
- N1 (duckworth-0058): a grant the user writes by hand isn't a request, so REQ-GRANT-1's bounds don't
|
||||
reach it as a request. REQ-GRANT-2 has the loader refuse a hand-written grant with a wildcard, a
|
||||
shell, an empty command or no rotate-by date. Row 210's key entry already carries one (`rotateBy`,
|
||||
origin/gizmoduck/row210-on-199-r2 `agents/gizmoduck/work/queue-210/DESIGN.md:144`).
|
||||
- B1 (duckworth-0057, mos-1129): a grant the code couldn't finish is undone at once on the stack's side.
|
||||
What it left on the host or service stays visible as pending until it is removed, as for a revoke.
|
||||
- B2 (duckworth-0057, mos-1129): Mos chose Duckworth's second option. Only an Approve creates a grant,
|
||||
and the code uses a grant only when it has a matching Approve record. A grant written by hand makes
|
||||
nothing. Jason's Q188 gives the reason: "Disallowing the agents to create grants autonomously is a
|
||||
necessary evil for better security" and "Upon approval, the grant is created programmatically." Row
|
||||
210's hand-written grants stay a test path until #436a moves `host.run` to grants made by Approve. r2
|
||||
and r3 had a hand path in the business file, and r4 takes it out, with r3's load check on hand grants
|
||||
(duckworth-0058 N1) and the note that a revoke never rewrites the user's file (duckworth-0058 N2).
|
||||
The same-uid write to the stack's own store stays the B7 residual, and the top of this draft names it
|
||||
for Jason.
|
||||
- C1 (duckworth-0058, sage-1538): `account.create` is the hard wait for any new external account, not
|
||||
only a grant (REQ-WAIT-1, `vocabulary.mjs:43-46`, `roles/pm.md:55`). It stays as version 1.7 has it.
|
||||
Only `credential.mint` is chief-only, and a grant that makes an account is a `credential.mint`
|
||||
decision (N4), so a PM's sign-up for a service routes as before.
|
||||
- Gizmoduck's machine-grant r2 (eb4c756a1, gizmoduck-0067): enrollment is a request the user approves
|
||||
and the stack runs (mos-1120), and a host user with sudo is enrolled by name, the user's Approve
|
||||
covering that user (mos-1125). REQ-GRANT-2's machine key says both. Their design gives revoke to the
|
||||
user and the tester only, and their Q-S5 asks Jason whether the assistant gets it too. REQ-GRANT-4
|
||||
follows Mos's ruling (mos-1124 d) until Jason answers Q-S5, and then matches his answer.
|
||||
- N2 (duckworth-0058), for #436: a revoke by the assistant or the tester can reach a grant the user
|
||||
wrote by hand. The revoke marks the grant revoked in the stack's own record and never rewrites the
|
||||
user's business file.
|
||||
- N4 (duckworth-0057): a decision carries one action (`a.action`, broker.mjs:1678 on origin/refactor). A
|
||||
request that makes an account is raised as `account.create` and names its credential, so the decision
|
||||
shape doesn't change.
|
||||
- N5 (duckworth-0057): once `host.sudo` is routed, a raise for it that cites the spec and isn't
|
||||
within-role goes to the arbiter for its domain, like any gated raise (broker.mjs:1677-1678 on
|
||||
origin/refactor), not to the user. REQ-CRED-4's grant and allowlist bound what the arbiter can allow.
|
||||
Mos to say whether that is wanted or `host.sudo` should go to the user in any case.
|
||||
- N6 (duckworth-0057): the broker checks only that the chief of staff raised a grant request. Which
|
||||
role asked the chief, and through whom, is in the role contracts (step 6 of "When this version
|
||||
lands"), not a broker check. REQ-GRANT-1 says so.
|
||||
- N1 (duckworth-0057, mos-1129): the approval binds the target or its enrolled identity.
|
||||
- N2 (duckworth-0057, mos-1129): a revoke during creation stops it, and nothing it made stays usable.
|
||||
- N3 (duckworth-0057, mos-1129): landing step 6 lists the role contract updates (`roles/pm.md:55`,
|
||||
`roles/chief-of-staff.md:75`). A `credential.mint` decision raised before 1.8, or one without the
|
||||
grant fields, makes nothing when it is approved.
|
||||
- N4 (duckworth-0057, mos-1129): a decision carries one action (`a.action`, broker.mjs:1678 on
|
||||
origin/refactor). A grant that makes an account is one `credential.mint` decision: the method in the
|
||||
grant says it makes an account, and the inbox shows the account name before Approve. The user clicks
|
||||
once, and there is no separate `account.create` action for it. Gizmoduck's machine-grant r2 reads it
|
||||
the same way.
|
||||
- N5 (duckworth-0057, mos-1129): `host.sudo` keeps the arbiter route version 1.7 set for
|
||||
`git.push.remote`. A raise for it that cites the spec and isn't within-role goes to the arbiter for
|
||||
its domain (broker.mjs:1677-1678 on origin/refactor), and the grant and its allowlist still limit the
|
||||
command. In manual mode the decision goes to the user. The top of this draft names this for Jason as a
|
||||
change in who decides a root command on another host.
|
||||
- N6 (duckworth-0057, mos-1129): the broker enforces only that the chief of staff raised a grant request.
|
||||
The rest of the chain of command is the messaging lists and the role contracts (step 6 of "When this
|
||||
version lands"). REQ-GRANT-1 says so.
|
||||
- Approving a grant doesn't by itself let a command run without a click. That needs REQ-CRED-4 and
|
||||
`host.sudo` in the routed lists, step 5 of "When this version lands" (gizmoduck-0062 item 4i).
|
||||
- Which roles may request: Q188 says "Not all agents are capable or authorized to request directly. It
|
||||
@@ -274,11 +293,11 @@ Under "Risks and open questions", a new bullet:
|
||||
or chief of staff" as one role under two names. That reading is Mos's, so the top of this draft puts it
|
||||
to Jason at approval.
|
||||
- REQ-CRED-4 keeps row 210's conditions (origin/gizmoduck/row210-on-199-r2,
|
||||
agents/gizmoduck/work/queue-210/DESIGN.md:376-392): the definition declares the kind, the grant names
|
||||
the agent, an exact argv-prefix allowlist with wildcards refused, the key issued, and only a reviewed role
|
||||
change adds the action. Row 210 put the grant in a hand-edited business file. Under 1.8 the grant is
|
||||
what Approve records, so "the business file grants that agent that host" becomes "a grant names that
|
||||
agent and that host".
|
||||
agents/gizmoduck/work/queue-210/DESIGN.md:376-392): the definition declares the kind, the grant names the
|
||||
agent, an exact argv-prefix allowlist with wildcards refused, the key issued, and only a reviewed role
|
||||
change adds the action. Row 210 put the grant in a hand-edited business file, which stays a test path until
|
||||
#436a. Under 1.8 the grant is what Approve records, so "the business file grants that agent that host"
|
||||
becomes "a grant names that agent and that host".
|
||||
- Revoke: Q188 says "you, Mos or the tester". Mos is Jason's assistant (REQ-ROLE-4), so the text says the
|
||||
assistant, limited to grants in its own organization, and the tester only on a dev instance (Q173).
|
||||
Mos accepted this with those limits (mos-1124 d).
|
||||
@@ -287,13 +306,12 @@ Under "Risks and open questions", a new bullet:
|
||||
REQ-WEB-2, which stays with the Console decide buttons amendment (Vikunja 19/266). That amendment, or a
|
||||
later version, moves Approve into the Console.
|
||||
- Roles already use a scoped Gitea token (`<read|write>:<category>`, all and admin never granted,
|
||||
`packages/business/src/vocabulary.mjs:105-106` on origin/refactor). It is a likely Gitea unit, not a
|
||||
settled one. Only the machine key is
|
||||
designed so far. Gitea and GitHub are a later #436 draft, and minting a Gitea token needs an admin
|
||||
credential the user enters, which is a design of its own (Gizmoduck's draft section 11). GitHub's
|
||||
rights unit isn't settled. So the text leaves both units to a later design Jason approves (mos-1124 f),
|
||||
and keeps only the bounds: an expiry, and never the all or admin scope. The PRD names outcomes and
|
||||
checks, not the grant code's steps, as REQ-CRED-3 does.
|
||||
`packages/business/src/vocabulary.mjs:105-106` on origin/refactor). It is a likely Gitea unit, not a settled
|
||||
one. Only the machine key is designed so far. Gitea and GitHub are a later #436 draft, and minting a Gitea
|
||||
token needs an admin credential the user enters, which is a design of its own (Gizmoduck's draft section
|
||||
11). GitHub's rights unit isn't settled. So the text leaves both units to a later design Jason approves
|
||||
(mos-1124 f), and keeps only the bounds: an expiry, and never the all or admin scope. The PRD names outcomes
|
||||
and checks, not the grant code's steps, as REQ-CRED-3 does.
|
||||
- Jason expects the inbox Approve and the Gitea and GitHub grants by 10-27 (Q188 point 6). That is a
|
||||
delivery date, so it is in the source and not in the requirement text.
|
||||
- This draft follows the PRD's own style: plain words, no semicolons in new sentences, and the status
|
||||
|
||||
Reference in New Issue
Block a user