Repository navigation
Conversation
A Go app whose every page and write asks a local Permit PDP through the Go SDK, with a panel that shows each check and why the PDP decided it. It covers role derivation down a five-level tree, partner grants on named trucks, attribute-based resource sets, tenant isolation, lifecycle rules, time-boxed access, revocation and organization merges. The rules Permit's editor can't express are custom Rego installed through GitOps. Adds the folder's CI workflow (Go and Rego checks), its pre-commit hooks, a Dependabot entry and the README row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t operates Acting for the operating organization, any operational action on a truck it operates passed the tenant-isolation rule, so a role the owner granted (which reaches the truck through relationships whatever tenant is passed) allowed it: Acme's Dallas technician could service DAL-04 by acting for Lone Star. Now only a grant from the operator's own roles (operator_org_allow) opens such a truck, and the denial explains which roles were missing. Adds Rego tests that model root.rego's two allow rules with the generated policy allowing, and two `make verify` rows (53 checks now). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…agging write from a done one Reads of the PDP's data and policy turned every error into "nothing there". So with OPA unreachable, WaitGone and WaitUnlinked reported the deleted data gone after a millisecond, `make verify` said the custom rules were missing and sent people to `make apply-policy`, and a denial without debug output was explained as "No role, relationship or rule ... lets ...". - pdp: OPAData, Debug, DebugMany, CustomPolicyVersion and the waits return errors. A 200 without a result (or a 404 module) is absent; anything else is an error. The waits return a *NotCaughtUpError when the PDP lags, so callers can tell lag from an unreadable PDP. Status reports RulesUnknown instead of "missing" when the policy couldn't be read. - explain: Unavailable gives the verdict without a guessed reason. - server: the waits after a write note what the PDP doesn't confirm, and the action then answers with that instead of its success message (the write itself stays done). A transfer still redirects. - policy: RequiredByRoot (order-insensitive) and Version sit next to RootAllow, and a test ties apply-policy's patch to the reader. - permitapi: HTTPError for calls made without the SDK, recognised by Status. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`make setup` and `make reset` delete what the seed doesn't have, and they could do it in an environment other than the one in .env: a PERMIT_API_KEY exported in the shell won over .env (for the commands and for Compose), and .env was looked up in every parent folder. - settings: only the key in .env is used; a different one in the shell is an error. .env is looked up in the working directory and next to the program (and bin/'s parent), never further up. Load no longer writes the process environment (PORT is a setting). The parser reads quotes and " #" comments the way Docker Compose does, so the app and the PDP get the same key. - sync: resolves the key's project and environment (/v2/api-key/scope), prints them before any write, stops when PERMIT_PROJECT or PERMIT_ENV names another, and lists set rules and condition sets in the key's own environment. Raw list errors are permitapi.HTTPError, so a 429 is retried and an allowed status applies. - make pdp: unsets the shell's key so Compose takes the one in .env. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…orted Go CI built with the `go 1.23` directive, a release without security fixes, and had no dependency audit, unlike the portal demo's workflow. govulncheck found 17 standard-library vulnerabilities the code reaches (HTTP server and client), even on go1.26.4. - go.mod: go 1.26.0, toolchain go1.26.9 (setup-go reads the toolchain line); govulncheck v1.8.0 then reports none the code reaches. - workflow: a govulncheck job gates the Go job, which also runs staticcheck and the tests under -race. Both tools run as `go run module@version`, checked against the Go checksum database. - errors.AsType where the code inspects error types. - README: Go 1.26 or later, and `make test` needs opa 1.0 or later (--v0-compatible). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server listens on 127.0.0.1 and has no sign-in, but it took a POST with any Content-Type, Origin and Host. A page open in the presenter's browser could post a text/plain body (no CORS preflight) to delete an organization as anyone, or rebind its host name to 127.0.0.1 to read the answers. Every request must now name localhost or 127.0.0.1 as its host, writes go through http.CrossOriginProtection, and an action must be JSON. The server also gets a ReadHeaderTimeout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… on it The page returned the acting organization's whole roster, with titles, roles and certifications, whatever the bulk check answered: the checks only decided the buttons. A broker or a partner technician acting for a customer saw its staff and their grants. The page is now denied, with the PDP's reason, unless at least one of its checks (manage users, a team's activity, roles on a site) is allowed, and the page shows the denial like the Access page does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… not a stale copy Certification and break-glass changes compared the request with the app's in-memory copy of the person's attributes, read at start-up, and wrote that copy back whole. After a reset or a dashboard edit while the app ran, an org admin's tier 2 change could give tier 3 back without the platform-staff check, and a break-glass grant could write stale certifications back. Both actions now read the person's attributes from Permit inside the action, decide which checks run against them, and write them back with only the one attribute changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Person, organization, truck, site and role keys from the server went into attributes and links unescaped, while every text field already went through esc(). They are Permit keys or seed data, but a key with a quote in it would have broken out of the attribute. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comments said schema writes regenerate the GitOps branch and that Permit may regenerate root.rego after dashboard changes. Permit's policy sync does neither: root.rego is replaced only when Permit merges a policy-library update into the branch. The managed comment in root.rego also named the demo's old folder. Adds a test that custom.rego's platform org literal is model.PlatformOrg. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
settings.Client silences the SDK's logger, which was the only place that named the failing object, and most callers returned the SDK's error as is: `sync failed: ErrorCode: UnexpectedError, ... 500 Internal Server Error` didn't say which of about a hundred calls failed. Every API error in sync, the app's start-up load and its actions now names what was being listed, created, updated or deleted. Co-Authored-By: Claude Opus 5.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.
What this adds
fleet-ops-demo/: a multi-tenant fleet operations app on the Permit Go SDK (permit-golangv1.2.8). Customerorganizations own regions, sites, trucks and teams; partners get access to single trucks; a platform operator
("Fleet Ops") manages every organization. Every page and every write is decided by a local container PDP
(
pdp-v2:0.9.16), and a panel beside each page shows every check, the PDP's answer and why: the relationship route,the attribute rule's conditions with the values evaluated, the tenant-isolation verdict and the custom policy version.
It shows 17 scenarios (the README has the walkthrough): role derivation down a five-level tree, scoped admin
delegation, nested organizations, re-parenting, team supervisors, partner access on named trucks, owner vs.
operator, a broker across three organizations, certification-gated service, attribute-based resource sets,
tenant isolation, lifecycle gating, time-boxed break-glass access, revocation, organization merges and audit.
Most of it is Permit's built-in RBAC, ReBAC and ABAC. Tenant isolation and the owner/operator, certification,
lifecycle and time-boxed rules are custom Rego installed in the environment's GitOps branch by
make apply-policyand ANDed into every allow; the README says which scenario uses which.
Also: the folder's CI workflow (govulncheck, gofmt, vet, staticcheck, race tests,
opa checkandopa test), itspre-commit hooks, a Dependabot entry for its Go module and the root README row.
How it was checked
operator's tenant key was renamed. Every step behaved as the README describes; writes reached the PDP 0.6 to 0.8 s
after the API call; the original 51 pre-flight checks (
make verify; 53 now, with the two H1 rows) pass after a reset.go test -race ./...(every package), 41/41 Rego tests on OPA 0.42.2 and on 1.21.1with
--v0-compatible, staticcheck, govulncheck (0 reachable vulnerabilities), typos, gitleaks, actionlint andzizmor, all clean locally.
pdp-v2:0.9.16denies thetwo bypass cases with
acting_org_mismatch, keeps the operator's own access, and the original 51 pre-flight checksstill match.
make setup. The tenant-key rename needs a freshenvironment; the rename is mechanical, and the Rego and Go tests use the new key.
Review
Reviewed with two Go verifiers (idioms, risk) and one fixer pass. Every finding and what happened to it:
acting_org_okrequires the operator's own roles (operator_org_allow); 10 Rego tests, 2 new pre-flight rows (53 checks)make setup/resetcould act on a different environment than.envnames.envkey only (a different shell key is an error), no parent-folder lookup,cmd/syncresolves and prints the key's scope and refuses a mismatchhttp.CrossOriginProtection, JSON-only writes,ReadHeaderTimeoutroot.regoroot.regoon schema or dashboard changes; only a base-policy update can overwrite it. Misleading comments correctedesc()on 12 interpolationslistRawerrors carried no status codepermitapi.HTTPError, recognised by the retry logicroot.regocontract tested on two separate fixturesRootAllow, with a contract testcmd/verify,cmd/serverand most action happy paths still untested.envparsing differed from ComposeFor the reviewer
@zeevmoney, over to you:
web/only got escaping and a denied branch for the People page.argument names, list calls that return nothing, a delete-and-recreate race in the PDP). Keep them here, or move
them to tickets?
make test.🤖 Generated with Claude Code