Skip to content

Commit f5cd0ba

Browse files
committed
Add masked API key lookup
Expose organization-scoped API key metadata without admitting plaintext or API key lifecycle into Terraform. Use the tagged SDK's paginated search and enforce exact-name identity in the provider, with focused unit and opt-in acceptance coverage.
1 parent e4e3439 commit f5cd0ba

18 files changed

Lines changed: 997 additions & 28 deletions

File tree

.github/workflows/acceptance.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ jobs:
4646
package: ./internal/datasources/app
4747
project_id_required: true
4848
app_fixture_required: true
49+
- name: API key data source
50+
package: ./internal/datasources/apikey
51+
project_id_required: true
4952
- name: Deployment data source
5053
package: ./internal/datasources/deployment
5154
project_id_required: true

CHANGELOG.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ First public v1 release candidate:
88

99
- Provider configuration for `api_key`, `base_url`, and `project_id`.
1010
- Durable `kernel_project`, `kernel_browser_pool`, and `kernel_extension` resources.
11-
- Lookup-only `kernel_app`, `kernel_browser_pool`, `kernel_deployment`, `kernel_project`, `kernel_profile`, `kernel_proxy`, and `kernel_extension` data sources.
11+
- Lookup-only `kernel_api_key`, `kernel_app`, `kernel_browser_pool`, `kernel_deployment`, `kernel_project`, `kernel_profile`, `kernel_proxy`, and `kernel_extension` data sources.
1212
- Stable import for every registered resource, including project-qualified browser-pool and extension forms.
1313
- Unit tests, generated Terraform docs, Terraform examples, CI checks, and an opt-in live acceptance matrix.
1414

1515
Intentionally deferred from the first public v1 because their durable API, SDK, or sensitive-state contracts are incomplete:
1616

1717
- Runtime browser/session operations such as acquire, release, flush, app invocation, screenshots, logs, live view, and force recovery.
1818
- API key, profile, proxy, and deployment resources.
19-
- API key data source.
2019
- `force_destroy` browser-pool deletion.
2120
- Terraform Plugin Framework code generation.
2221

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Resources:
2020

2121
Data sources:
2222

23+
- `kernel_api_key`
2324
- `kernel_app`
2425
- `kernel_browser_pool`
2526
- `kernel_deployment`

docs/acceptance.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ Actions secrets and must not be printed.
5050
| `kernel_proxy` data source | Test present | A uniquely created managed datacenter proxy is read by canonical ID and exact name through explicit and provider-default project scope; durable type/protocol metadata, no-drift planning, and post-cleanup coded `not_found` are verified without fixture credentials. | None. |
5151
| `kernel_app` data source | Test present | A release-owned running app version is read by exact name/version through explicit and provider-default project scope; canonical deployment metadata and no-drift planning are verified without invocation. Unit coverage verifies action-name and environment-key flattening without environment values. | Keep `KERNEL_ACC_APP_NAME` and `KERNEL_ACC_APP_VERSION` pointed at exactly one running app version in the acceptance project. |
5252
| `kernel_deployment` data source | Test present | The deployment backing the release-owned app fixture is read by canonical ID through explicit and provider-default project scope; direct GET metadata and no-drift planning are verified without logs or event streams. Unit coverage verifies that only environment variable names enter state. | Keep the release-owned app fixture running so its deployment ID remains readable. |
53-
| `kernel_api_key` data source | Deferred; unregistered | No provider surface yet. | Wait for a tagged SDK with exact-name filtering, then add masked ID/name lookup acceptance. |
53+
| `kernel_api_key` data source | Test present | A uniquely created project-scoped key is read by canonical ID and byte-exact name; masked metadata, no plaintext state, ambiguity behavior, no-drift planning, cleanup, and coded post-cleanup absence are covered. | Run with an organization-wide administrative `KERNEL_API_KEY`; project-scoped credentials cannot create or delete the fixture. |
5454
| Profile, proxy, deployment, and API-key resources | Deferred; unregistered | No provider surfaces yet. | Enter the matrix only after their documented API/SDK/state blockers are resolved and implementation lands. |
5555

5656
"Test present" describes code in the repository; it does not claim a run
5757
against the release commit. The release record below supplies that evidence.
5858

5959
## Current Commands
6060

61-
Run the ten existing packages independently for fast failure isolation:
61+
Run the eleven existing packages independently for fast failure isolation:
6262

6363
```sh
6464
go test -count=1 -timeout=30m -v ./internal/resources/project -run TestAcc
@@ -69,6 +69,7 @@ go test -count=1 -timeout=30m -v ./internal/datasources/extension -run TestAcc
6969
go test -count=1 -timeout=30m -v ./internal/datasources/profile -run TestAcc
7070
go test -count=1 -timeout=30m -v ./internal/datasources/proxy -run TestAcc
7171
go test -count=1 -timeout=30m -v ./internal/datasources/app -run TestAcc
72+
go test -count=1 -timeout=30m -v ./internal/datasources/apikey -run TestAcc
7273
go test -count=1 -timeout=30m -v ./internal/datasources/deployment -run TestAcc
7374
go test -count=1 -timeout=30m -v ./internal/datasources/browserpool -run TestAcc
7475
```

docs/api-key-state.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
## Decision
44

5-
The masked `kernel_api_key` data source is safe to implement after a tagged
6-
Kernel Go SDK exposes the API's exact-name list filter.
5+
The masked `kernel_api_key` data source is supported. It uses the tagged Kernel
6+
Go SDK's paginated query filter, then enforces byte-exact name equality in the
7+
provider and diagnoses ambiguous names.
78

89
The `kernel_api_key` resource is deferred. Its Terraform state shape is
910
accepted below, but Create and Rotate must not ship until the API provides
@@ -51,9 +52,11 @@ has these properties:
5152
- A deleted key is hidden from ordinary Get and a repeated Delete returns
5253
`not_found`.
5354

54-
The API supports an exact-name List filter. It is generated in the pending Go
55-
SDK v0.77.0 release, so the provider must wait for that tag rather than adding
56-
direct HTTP or a second client.
55+
The API supports substring query today and has a dedicated exact-name List
56+
filter pending in Go SDK v0.77.0. The data source does not require the pending
57+
filter: it scans every query page, post-filters names byte-for-byte, and
58+
deduplicates canonical IDs. The provider still uses only the tagged SDK and
59+
does not add direct HTTP or a second client.
5760

5861
## Future Resource State
5962

@@ -180,9 +183,9 @@ replay contract.
180183

181184
## Masked Data Source
182185

183-
The data source is independent of plaintext lifecycle and may ship first. It
184-
should accept exactly one of canonical `id` or exact `name`, scan all pages for
185-
name lookup, deduplicate by ID, and diagnose zero or multiple non-deleted
186+
The data source is independent of plaintext lifecycle. It accepts exactly one
187+
of canonical `id` or exact `name`, scans all pages for name lookup, deduplicates
188+
by ID, and diagnoses zero or multiple non-deleted
186189
matches. Expired-but-not-deleted keys remain visible because they are durable
187190
records under the current API status definition. The API's name filter follows
188191
the production database's case- and accent-insensitive collation; the provider
@@ -195,7 +198,6 @@ or provider-authentication identity.
195198

196199
## Unblocking Checklist
197200

198-
- Tag an SDK release containing the exact API-key name filter.
199201
- Add replayable idempotency for API-key Create and Rotate.
200202
- Add a stable current-key/project-scope signal or coded self-rotation
201203
rejection plus effective-scope metadata.

docs/architecture.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Core v1 resources:
5656

5757
Core v1 data sources:
5858

59+
- `kernel_api_key`
5960
- `kernel_project`
6061
- `kernel_browser_pool`
6162
- `kernel_profile`
@@ -67,17 +68,17 @@ Core v1 data sources:
6768
Late or conditional v1 work:
6869

6970
- `kernel_proxy` resource, after write-only credential/import semantics are accepted and a tagged SDK exposes in-place rename
70-
- masked `kernel_api_key` metadata lookup
7171
- `kernel_api_key` resource, only after plaintext-once, retry, rotation, import, and provider self-use semantics are accepted
7272
- project limits, only after their lifecycle is clearly separate from basic project management
7373

7474
Blocked candidates must remain unimplemented until the API and a tagged SDK expose the required durable contract. Provider code must not guess missing semantics, patch generated SDK code, or add a fallback HTTP client to bypass the durable client module.
7575

7676
The accepted plaintext, import, rotation, and self-use model for API keys is
7777
defined in [API Key Terraform State Design](api-key-state.md). The masked data
78-
source may proceed after the exact-name SDK surface is tagged. The resource
79-
remains blocked on replayable Create/Rotate idempotency and a current-key
80-
rotation guard with effective authenticated project-scope metadata.
78+
source scans the tagged SDK's paginated query results and enforces byte-exact
79+
name equality in provider code. The resource remains blocked on replayable
80+
Create/Rotate idempotency and a current-key rotation guard with effective
81+
authenticated project-scope metadata.
8182

8283
`kernel_deployment` remains core v1 scope but is currently blocked until a
8384
tagged SDK exposes source provenance, the API supports deterministic durable

docs/data-sources/api_key.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "kernel_api_key Data Source - Kernel"
4+
subcategory: ""
5+
description: |-
6+
Lookup masked metadata for a non-deleted Kernel API key by canonical ID or exact name.
7+
---
8+
9+
# kernel_api_key (Data Source)
10+
11+
Lookup masked metadata for a non-deleted Kernel API key by canonical ID or exact name.
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Optional
19+
20+
- `id` (String) Canonical API key ID.
21+
- `name` (String) API key name for exact lookup. Names are not unique, so ambiguous matches fail.
22+
23+
### Read-Only
24+
25+
- `created_at` (String) API key creation timestamp.
26+
- `created_by_email` (String) Email address of the key creator.
27+
- `created_by_id` (String) Kernel user ID of the key creator.
28+
- `created_by_name` (String) Display name of the key creator, when available.
29+
- `expires_at` (String) API key expiration timestamp, or null when the key does not expire.
30+
- `masked_key` (String, Sensitive) Masked API key metadata. Plaintext is never returned or stored.
31+
- `project_id` (String) Project ID for a project-scoped key, or null for an organization-wide key.
32+
- `project_name` (String) Project name for a project-scoped key, when available.

docs/migration-v1.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ path. Managing future content replacement requires Terraform 1.11 or later plus
6464

6565
## Newly Available Lookups
6666

67-
V1 adds lookup-only app and browser-pool data sources alongside project,
68-
profile, proxy, and extension lookups. Data sources do not adopt or mutate the
69-
remote object. Exact lookup fails when no object or multiple objects match.
67+
V1 adds lookup-only API-key, app, browser-pool, and deployment data sources
68+
alongside project, profile, proxy, and extension lookups. Data sources do not
69+
adopt or mutate the remote object. Exact lookup fails when no object or multiple
70+
objects match. API-key lookup returns masked metadata only.
7071

7172
## Deferred Surfaces
7273

docs/release.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ Use this checklist before publishing a Kernel Terraform provider version.
2323
- Review the [v1 migration guide](migration-v1.md) and include it in the release notes.
2424
- Use the commands and status table in `docs/acceptance.md` as the single source of truth. The manual `Acceptance` workflow runs all current packages in parallel; add each new package in the same PR as its first live test and keep live tests out of normal PR CI.
2525
- Process-level timeouts can bypass Go test cleanup. After an interrupted or hard-timeout run:
26-
1. In the Kernel dashboard or durable API, find projects, browser pools, extensions, profiles, and proxies named `kernel-tf-*` that were created during the failed workflow run.
26+
1. In the Kernel dashboard or durable API, find projects, browser pools, extensions, profiles, proxies, and API keys named `kernel-tf-*` that were created during the failed workflow run.
2727
2. Delete leaked browser pools first with `force=false`. If deletion conflicts with a lease, wait for the lease to end; do not force-release or recover the browser from Terraform cleanup.
2828
3. Delete leaked extensions after removing any durable browser-pool references to them. Do not mutate pools or running browsers implicitly.
2929
4. Delete leaked profiles and managed datacenter proxies after removing durable references. Do not run proxy health checks as cleanup.
30-
5. Delete a leaked project only after its child resources are gone and the organization still has another active project.
31-
6. Do not delete the release-owned app fixture; it is not created by the acceptance run.
32-
7. Read each test-owned canonical resource ID and require a 404 before considering cleanup complete.
30+
5. Delete leaked API keys with an organization-wide administrative key. Never delete the credential running the acceptance workflow.
31+
6. Delete a leaked project only after its child resources are gone and the organization still has another active project.
32+
7. Do not delete the release-owned app fixture; it is not created by the acceptance run.
33+
8. Read each test-owned canonical resource ID and require a 404 before considering cleanup complete.
3334
- Verify unscoped API calls send no `X-Kernel-Project-Id` header; it is sent only when a resource-level `project_id` or the provider default resolves a project.
3435
- Confirm `terraform-registry-manifest.json` contains protocol `["6.0"]` for Terraform Plugin Framework.
3536
- Confirm the repository license before the first public release. The release workflow fails unless a non-empty `LICENSE` exists.

examples/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ Use local development overrides while the provider is unreleased. See the root [
1818
- [basic-browser-pool](basic-browser-pool) creates a minimal durable browser pool.
1919
- [design-preview-browser-pool](design-preview-browser-pool) shows a browser pool shaped for repeated design-preview checks without modeling the browser sessions themselves.
2020
- [extension](extension) uploads an immutable extension archive and tracks exact content changes with `filesha256`.
21-
- [lookups](lookups) shows read-only app, browser-pool, deployment, project, profile, proxy, and extension data sources.
21+
- [lookups](lookups) shows read-only API-key, app, browser-pool, deployment, project, profile, proxy, and extension data sources.
2222
- [project](project) creates a durable Kernel project with an explicit unique name.
2323
- [project-scoped-browser-pool](project-scoped-browser-pool) places a browser pool in an explicit project, overriding the provider-level `project_id` default.

0 commit comments

Comments
 (0)