Skip to content
🛡️ adminadmin@example.com · Domain admin in Acme Corp
🏗️ operatoroperator@example.com · platform grant, no Domain

Chapter 9 — Two-party governance

Refresh both sessions

Device-code tokens live one hour. You are probably past that.

bash
plexctl login --domain-id "$DOMAIN_ID"
bash
plexctl login --profile-name operator --platform

Presenter note: take this slide even if nothing has failed yet — the next chapter's poll loop is a bad place to discover an expired token.

🛡️ adminadmin@example.com · Domain admin in Acme Corp

A Project that wants to build something

bash
PROJECT_ID=$(plexctl project create \
  --domain "$DOMAIN_ID" \
  --slug provision-demo \
  --display-name "Provision demo" \
  --output json | jq -r '.id')
echo "$PROJECT_ID"

Back in the tenant hat. This Project has a Blueprint available to it and no way to pay for anything.

🏗️ operatoroperator@example.com · platform grant, no Domain

First, the Cloud itself

bash
plexctl cloud assignment grant \
  --cloud-id "$CLOUD_ID" \
  --project-id "$PROJECT_ID" \
  --profile operator \
  --output json | jq -r '.state, .materialised'

Two decisions, two people. The Cloud's operator says who may consume the Cloud; the credential's owner says who may spend the credential. This is the first one, and it lands approved outright — the operator made the Cloud, so they decide its consumers.

Presenter note: the point to land is that holding a credential does not let you put a Project onto somebody else's Cloud. Skip this slide and the next command fails with cloud_not_usable_in_project.

🛡️ adminadmin@example.com · Domain admin in Acme Corp

Ask for the credential

bash
ASSIGNMENT_ID=$(plexctl credential assignment request \
  --project-id "$PROJECT_ID" \
  --cloud-credential-id "$CREDENTIAL_ID" \
  --output json | jq -r '.id')
echo "$ASSIGNMENT_ID"

The assignment lands in requested.

You cannot approve your own request. The platform splits the halves and will not let one principal hold both.

🏗️ operatoroperator@example.com · platform grant, no Domain

The other party has an inbox

bash
plexctl approval list --profile operator --status pending-approval --output json \
  | jq '.items[] | {id, kind, state, target_resource}'
json
{
  "id": "019fb9c9-ec31-70c8-b3c4-bfbe0fe4cc25",
  "kind": "credential_assignment",
  "state": "pending-approval",
  "target_resource": "cloudcredential:019fb9c7-fe03-7dcf-b671-382f2b307d6f"
}

The operator does not go hunting through your Project. Everything awaiting a decision collects in one queue.

The queue filters itself

Any signed-in principal may call it. There is no blanket gate.

Instead each row is checked on its own terms: an assignment row is visible only to a principal holding assign on the object in target_resource. The operator issued this credential, so it sees it. Anyone else gets an empty list — not an error.

And note what the operator cannot do:

text
plexctl: Permission Denied: credentialassignments ListCredentialAssignments: caller lacks project read on the owning Project

It decides an assignment for a Project it cannot even browse.

Find the row by what it spends

bash
APPROVAL_ID=$(plexctl approval list --profile operator --status pending-approval --output json \
  | jq -r --arg cred "$CREDENTIAL_ID" \
      'first(.items[] | select(.kind == "credential_assignment" and .target_resource == "cloudcredential:" + $cred) | .id)')
echo "$APPROVAL_ID"

The same id the requester printed, arrived at the other way round.

On a real stack the operator is a different person on a different machine, with no $ASSIGNMENT_ID in their shell. The id travels through the queue, not through a variable.

Approve

bash
plexctl approval approve "$APPROVAL_ID" \
  --profile operator --output json | jq '{state, materialised}'
json
{
  "state": "approved",
  "materialised": true
}

Two different statements.

approved is the decision. materialised is its consequence — the broker now holds a usable credential handle bound to this Project.

A decision that did not materialise would be a bug you can see.

🛡️ adminadmin@example.com · Domain admin in Acme Corp

Confirm from the owner's side

bash
plexctl credential assignment list --project-id "$PROJECT_ID" --output json \
  | jq '.items[] | select(.state == "approved") | {id, state, materialised, cloud_credential_id}'
json
{
  "id": "019fb9c9-ec31-70c8-b3c4-bfbe0fe4cc25",
  "state": "approved",
  "materialised": true,
  "cloud_credential_id": "019fb9c7-fe03-7dcf-b671-382f2b307d6f"
}

Owner requested. Credential holder approved. Never the same principal.

Enforced server-side, even on a single-tenant dev stack where both hats are on the same laptop.