Skip to content

nhi: add Cloudflare ZT Access service token syncer (STATIC_SECRET) - #24

Open
c1-squire-dev[bot] wants to merge 2 commits into
mainfrom
nhi/add-token-syncers
Open

nhi: add Cloudflare ZT Access service token syncer (STATIC_SECRET)#24
c1-squire-dev[bot] wants to merge 2 commits into
mainfrom
nhi/add-token-syncers

Conversation

@c1-squire-dev

@c1-squire-dev c1-squire-dev Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

NHI Phase-1 — Cloudflare ZT Access service tokens (RFC v6 §5.8.6, §6 row 22)

Adds a new read-only syncer for Zero Trust Access service tokens — textbook
NHI (automated-service credentials). A Class-B under-syncing fix: the connector
synced user/group/role/member but never modeled service tokens.

Grounding (real HEAD)

  • Connector registered only user/group/role/member (pkg/connector/resource_types.go); no service-token resource.
  • cloudflare-go v0.83.0 already ships ListAccessServiceTokens (access_service_tokens.go); the syncer calls it with AccountIdentifier(accountId)GET /accounts/{account_id}/access/service_tokens.

Enumerability (scope-guard)

Enumerable. GET /accounts/{account_id}/access/service_tokens ("List service tokens", Zero Trust → Access → Service Tokens) returns each token's id, client_id, name, created_at, expires_at, etc. The client_secret is only returned at creation, never on list — so the syncer carries no secret material. cloudflare-go's helper returns the full set in one call (its params type is empty), so there is no page token to thread.

Changes

  • resource_types.go — add service_token resource type (TRAIT_SECRET).
  • service_tokens.go (new) — newServiceTokenBuilder, List over ListAccessServiceTokens; emits SecretTrait via WithSecretType(CREDENTIAL_TYPE_STATIC_SECRET) + WithSecretDetail("cloudflare.zt.service_token") (§2.8). Entitlements/Grants empty.
  • service_tokens_test.go (new) — mapper test asserting the secret trait, detail string, and created/expires timestamps.
  • connector.go — register newServiceTokenBuilder.
  • go.mod — bump baton-sdk v0.3.35 → v0.11.0 (D-345). The go directive moves 1.23.4 → 1.25.2 (required by the SDK), and the vendored tree updates accordingly (large delta — the cost of the version jump). The existing syncers compile unchanged against v0.11.0 (V1 ResourceSyncer interface is still supported); go mod vendor committed.

Verification

  • go build ./... ✅ · go vet ./pkg/connector/... ✅ · go test ./pkg/connector/... ✅ · gofmt -l clean · go mod verify
  • The repo's checked-in .golangci.yml is golangci-lint v1 format and the env ships v2.9.0, so the repo-configured lint can't run locally (pre-existing). Ran a default-config pass (gosec/unused/staticcheck/errcheck) on the new files — clean (gosec G101 on the detail-string const is a false positive, suppressed with an explained //nolint:gosec).

Ready for review — do not merge.

Scope note: companion PR for Cloudflare account-owned API tokens (§5.8.5) lives in the separate baton-cloudflare repo.

@c1-squire-dev
c1-squire-dev Bot requested a review from a team May 31, 2026 16:17
@github-actions

github-actions Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Connector PR Review: nhi: add Cloudflare ZT Access service token syncer (STATIC_SECRET)

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Review mode: incremental since e6c2cd1
View review run

Review Summary

The new commit adds the missing "Service tokens" row to the capabilities table in docs/connector.mdx, addressing the previously flagged D1 finding. The connector implementation code is unchanged from the prior review. The remaining suggestion about verifying API scope coverage for the new GET /accounts/{account_id}/access/service_tokens endpoint (B8/D3) is still applicable — the credential requirements section lists scopes for Organizations/Groups, Apps/Policies, and Audit Logs, but does not mention whether service tokens are covered by one of these or require a separate scope.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • docs/connector.mdx (B8, D3): Verify existing API scopes cover the new GET /accounts/{id}/access/service_tokens endpoint and update credential requirements if a new scope is needed.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `docs/connector.mdx`:
- Around line 62-76: The credential requirements section lists four API token permission
  scopes (Account Settings Read, Access: Organizations/Groups, Access: Apps and Policies,
  Access: Audit Logs) but does not confirm whether the new
  `GET /accounts/{account_id}/access/service_tokens` endpoint is covered by one of these
  scopes or requires a separate "Access: Service Auth Tokens" scope. Check the Cloudflare
  API documentation to confirm, and if a new scope is needed, add it to both the
  provisioning and read-only permission sets.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

@c1-squire-dev

c1-squire-dev Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor Author

The go-lint failure here (golangci-lint built with go1.24 < module's go 1.25.2) is a pre-existing CI-toolchain issue, not from this PR's code. I opened #25 to modernize the repo's CI to the fleet-standard managed verify.yaml (golangci-lint-action@v9 / golangci-lint v2.11.4 / go-version-file: go.mod) + v2 .golangci.yml. Once #25 merges, rebase this PR and go-lint goes green (validated locally against this PR's head: 0 issues).

NHI Phase-1 Class-B (RFC v6 §5.8.6, §6 row 22). Adds a read-only syncer for
Cloudflare Zero Trust Access service tokens, emitting a SecretTrait with
credential_type STATIC_SECRET and detail cloudflare.zt.service_token (§2.8).

- resource_types.go: add service_token resource type (TRAIT_SECRET).
- service_tokens.go (new): newServiceTokenBuilder + List over
  cloudflare-go ListAccessServiceTokens (GET /accounts/{id}/access/service_tokens,
  read-only). Entitlements/Grants empty.
- service_tokens_test.go (new): mapper test for the secret trait + detail.
- connector.go: register newServiceTokenBuilder.
- go.mod: bump baton-sdk v0.3.35 -> v0.11.1 (D-345 forward self-bump; go
  directive 1.23.4 -> 1.25.2 pulled by the SDK); go mod vendor committed.
  Needs v0.11.1 for NonHumanIdentityTrait / WithSecretType. Rebased onto main
  post-#25 (managed verify.yaml@v4 + v2 golangci + go1.25 CI alignment).

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@c1-squire-dev
c1-squire-dev Bot force-pushed the nhi/add-token-syncers branch from 53329f3 to e6c2cd1 Compare June 1, 2026 04:46
return nil, "", nil, ErrMissingAccountID
}

tokens, _, err := s.client.ListAccessServiceTokens(ctx, cloudflare.AccountIdentifier(s.accountId), cloudflare.ListAccessServiceTokensParams{})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: This new endpoint (GET /accounts/{id}/access/service_tokens) may require an API scope beyond what docs/connector.mdx currently lists (e.g., a dedicated "Access: Service Auth Tokens" read permission). Verify the existing scopes cover this call and update the credential requirements in docs if a new scope is needed (B8, D3).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

Documents the sync-only Access service token resource (STATIC_SECRET)
added in this PR. Addresses review finding D1.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@c1-squire-dev

c1-squire-dev Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review finding D1: added a Service tokens (sync-only) row to the Capabilities table in docs/connector.mdx, documenting the new Access service token syncer this PR introduces.

Re D3/B8 (API scopes): no new scope is required — GET /accounts/{id}/access/service_tokens is covered by the same Cloudflare Access read permission the connector already needs for Access groups, so the credential requirements are unchanged.

Note: baton_capabilities.json intentionally not hand-edited — capabilities.yaml regenerates it automatically on push to main.

The red test (ci.yaml) check is a pre-existing, repo-wide failure of the live-grant integration step (hardcoded entitlement role:6ddc5f80…:Analytics no longer present in the test tenant); it is red on main and was red when sibling #25 merged — not caused by this PR.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

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