Skip to content

feat(access): permission policies that refuse calls the caller lacks permission for - #28

Merged
Michael McQuade (giraffesyo) merged 3 commits into
canaryfrom
feat/access-control
Oct 23, 2026
Merged

Michael McQuade (giraffesyo) merged 3 commits into
canaryfrom
feat/access-control

Conversation

@giraffesyo

Copy link
Copy Markdown
Member

Summary

A new access package lets a test grant a set of permissions and see whether the code under test needs exactly those. The package covers Google Cloud IAM permissions, AWS IAM actions and Azure RBAC actions. Every stand-in takes a policy with WithPolicy:

  • It refuses a call that needs a permission the policy lacks, with the 403 the cloud answers, before any fault:
    • Compute Engine and Cloud Storage: forbidden.
    • EC2: UnauthorizedOperation.
    • S3: AccessDenied.
    • Azure: AuthorizationFailed, or LinkedAuthorizationFailed for a resource the request references.
  • Denials() lists the calls refused and what each lacked. Unused() lists grants no call needed. Used() lists what was needed.

A call needs its method's permission and those its request adds, from each API's reference:

  • Compute Engine: a boot disk created from an image needs compute.disks.create and compute.images.useReadOnly. Metadata needs setMetadata. A service account needs setServiceAccount and iam.serviceAccounts.actAs. An address insert needs either create or createInternal.
  • Cloud Storage: projection=full needs getIamPolicy, and an upload that replaces a live object needs storage.objects.delete.
  • EC2: a TagSpecification needs ec2:CreateTags.
  • S3:
    • HeadBucket needs s3:ListBucket, and deleting a version needs s3:DeleteObjectVersion.
    • An ACL header on PutObject needs s3:PutObjectAcl.
    • DeleteObjects is checked key by key, as S3 does it: a refused key is an AccessDenied entry in the result, and the rest are deleted.
  • Azure ARM: the linked checks for the subnet, public IP, network security group, network interface, virtual network, disk and image a write references.

A grant may use * and matches without regard to case. Grants are not checked against resources or condition keys: a grant covers every resource. Each package's documentation says so.

Testing

  • make check passes.
  • Each stand-in has tests through its official client library (sdktest/*/permissions_test.go). They cover a refusal and its error shape, a permission a request field adds, Azure's linked refusal, S3's per-key DeleteObjects result, and Used/Unused/Denials.
  • access has its own tests, run with -race.
  • make bench against canary, 6 runs each, with benchstat:
    • B/op and allocs/op are unchanged in every benchmark. A server without a policy only adds a nil check.
    • sec/op differences are within noise on a busy machine; confidence intervals were 8% to 70%.

Checklist

  • make check passes
  • New methods are tested through the official client library
  • Package documentation says where the stand-in differs from the real API

@giraffesyo
Michael McQuade (giraffesyo) merged commit 0ecd8c7 into canary Oct 23, 2026
12 checks passed
@giraffesyo
Michael McQuade (giraffesyo) deleted the feat/access-control branch October 23, 2026 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant