403 POLICY_DENIED and a reason that ends in “has no PolicyChangeApprovalRecord — it has never completed the Policy Governance approval flow.”
This applies to the policies shipped with Parmana too. The seed service copies them into your database but does not approve them, because an approval is a decision your own people make.
Approval takes two different people:
The server refuses an approval from the proposer, so one person can never make a policy take effect alone. How governance works in general: Policy governance.
1. Each approver makes a step up key
On the approver’s own machine:step-up.private.pem and sends only step-up.public.pem to the operator. Anyone holding the private key can approve policies as that person.
2. The operator adds the proposer and the approver
On the machine that runs Parmana, in the repository root, with the approver’s public key saved asbob-step-up.public.pem:
add prints the new key once. Give each person their own. Details: Manage API keys.
3. The proposer proposes the policy
The request body holds the full policy content and a reason:policyId and policyVersion in the content:
201 and "status":"PENDING_APPROVAL".
Only one proposal per policy name and version can be open at a time. A second one is refused with CONFLICT until the first is approved or rejected.
4. The approver reviews the change
The approver lists open changes. The response is{"changes":[...]}. Each entry holds pendingPolicyChangeId, proposedBy, reason, the proposed content and, under diff, the content in effect now next to the proposed one:
status may be PENDING_APPROVAL, APPROVED or REJECTED, or left out to list all. Only verified humans may list; any other key gets 403 NON_HUMAN_CALLER_DENIED.
5. The approver signs and sends the decision
To approve, on the approver’s machine, from the repository clone:200, and the body contains "status":"APPROVED" and "resolvedBy":"bob". From now on requests under this policy are decided by its rules.
To reject, sign with --action reject and send a reason:
"status":"REJECTED".
A signed step up authorization:
- is valid for 120 seconds (change it with
--ttl-seconds); - is valid for one change ID and one action only;
- can be used once.
Or approve from code, with an SDK
SDK 1.3.0 can do steps 3 to 5 from application code, and signs on the approver’s machine without a clone of the repository:signPolicyChangeStepUp() and approvePolicyChange() in TypeScript, parmana.crypto.sign_policy_change_step_up() and approve_policy_change() in Python. Examples are on the TypeScript SDK and Python SDK pages.
SDK 1.3.0 is published on npm and PyPI, so an approver can
npm install @parmana/sdk or pip install "parmana[verify]" and sign without the
repository.Errors
The full list of codes is in the error catalog.