
Evidence checkpoints
Documented point: For headless Codex workflows in a ChatGPT workspace, a service account is the documented non-human identity, so the playbook should assign one to the named continuous integration (CI)A software-development practice that automatically integrates and tests changes in a shared repository. Open glossary entry runner, scheduled job or shared integration rather than rely on an employee account. This is a ChatGPT workspace identity, not an application programming interface (API)A documented way for software systems to exchange requests and results. Open glossary entry Platform project service account. [OpenAI documentation: Service accounts.md]
Documented point: An owner or admin must create the service account, and the team must verify a pay-as-you-go workspace before treating service-account access as available. Current workspace entitlement and policy must be checked before provisioning. [OpenAI documentation: Service accounts.md]
Documented point: A service account needs direct minimum access because it does not inherit the creator’s permissions, and its token should be named, Codex-scoped and given a policy-allowed expiration. Workspace policy can constrain available expiry options. [OpenAI documentation: Service accounts.md]
Documented point: Because the full service-account token appears only once, the workflow should record only a secret-store reference, token name and expiry after secure capture rather than reproduce the value in CI configuration or documentation. [OpenAI documentation: Service accounts.md]
Documented point: On a shared or temporary trusted runner, service-account access tokens require Codex command-line interface (CLI)A text-based interface for running commands and tools. Open glossary entry 0.142.0 or later and can be supplied through CODEX_ACCESS_TOKEN without saving a local login. A saved login is reserved for a trusted machine. [OpenAI documentation: Service accounts.md]
Documented point: A CI job can use codex exec as the documented non-interactive interface, beginning in its default read-only sandbox and widening to workspace-write only when the named job justifies edits. Use danger-full-access only in a controlled environment. [OpenAI documentation: Non-interactive mode]
Documented point: The token should be held in a secret manager and used only on trusted runners, because public CI, forked pull requests and shared machines can expose credentials. A job-level environment readable by repository-controlled code is not a safe location for the token. [OpenAI documentation: Service accounts.md OpenAI documentation: Access tokens.md]
Documented point: A tested rotation replaces the token, updates the workflow, verifies the new access with a smoke test and then revokes the old token, while disabling or deleting an obsolete service account revokes all of its active tokens. Deletion cannot be undone, and a re-enabled account needs new tokens. [OpenAI documentation: Service accounts.md OpenAI documentation: Access tokens.md]
Set the Boundary: One Workspace Identity, One CI Job
The decision here is whether to create one non-human ChatGPT workspace identity for one named headless CI job. It is not a decision about an API Platform project service account, an API key or a convenient way to reuse an employee’s login. Those identities belong to different administrative boundaries. This playbook proceeds only when the proposed workload is a clearly bounded Codex CI task inside the relevant ChatGPT workspace.
For the worked example, the job is release-note-linter. Its proposed purpose is to perform a read-only check of release-note files on an approved trusted runner. A named engineering lead remains accountable for the service even though the runtime identity is non-human. The team must define the repository boundary, runner class, intended access and finite token lifetime before asking an owner or administrator to provision anything.
Documented fact, as of 6 October 2026: OpenAI’s service-account documentation describes a service account as the non-human identity for headless Codex workflows in a ChatGPT workspace. It also separates this arrangement from API Platform project service accounts and API keys, which use separate project access and billing. The procedural controls below are suggested governance measures built around those documented boundaries; they are not product guarantees.
Official quotation: “Service accounts let you run and scale headless Codex workflows across your organization without relying on an employee’s account.”
The quotation supports the identity choice, but it does not justify creating a broadly shared automation account. The safer operational unit is one identity tied to one declared job. That association gives reviewers a direct answer to four questions: which workload uses the identity, which human owns the workload, where it may run and which access is necessary. A generic account named for an entire engineering department cannot answer those questions without additional interpretation.
Write the one-job charter
Start with a short charter that distinguishes the job’s business purpose from its implementation. For release-note-linter, “checks whether release-note content meets an approved structure” is a purpose. “Runs Codex in CI” is merely an implementation. The distinction matters because access should follow the purpose: if the job only reports whether files meet a rule, a request to edit unrelated repository content would fall outside its charter.
Use the following example as a review template, not as evidence that any particular configuration is available:
| Decision field | Fictional example | Review question |
|---|---|---|
| Job name | release-note-linter |
Does this name identify one workflow rather than a department or platform? |
| Accountable human owner | Engineering lead recorded in the service register | Can this person approve continued use and organise review? |
| Purpose | Read-only validation of approved release-note files | Would the result still be useful without changing repository content? |
| Repository boundary | One approved release repository | Are other repositories explicitly out of scope? |
| Runner boundary | Organisation-controlled trusted runner class | Can public jobs, forked pull requests or unrelated code reach its secrets? |
| Access request | Minimum direct workspace access needed for the check | Has every requested role, group, plugin or connection been justified? |
| Lifetime | Finite, subject to the workspace’s permitted expiry choices | Is there a review before expiry rather than an assumption of permanence? |
Decision rule: if the team cannot describe the workload as one named job with one accountable human, one repository boundary and one trusted runner class, stop. Split the proposal into separately owned jobs or narrow it until those boundaries are explicit. The administrative overhead of separate identities is a meaningful trade-off, but it preserves attribution and prevents unrelated automation from silently depending on the same credential.
A finite token and trusted runner reduce only part of the exposure: repository instructions, inherited environment values and network-capable commands still need separate controls, as explained in Codex trust boundaries, sandboxes and secret filtering, which distinguishes project trust, sandboxing, approvals and secret filtering instead of treating a login method as a universal safety switch.
Reject personal-account and API-key substitutions
Run a terminology test before discussing access. Ask the proposer to complete this sentence: “The release-note-linter job will authenticate as ______.” The acceptable answer is a dedicated ChatGPT workspace service account, subject to the workspace gates below. “An engineer’s account”, “the team login”, “our API key” and “an API Platform project service account” identify either the wrong principal or the wrong product boundary.
Consider a negative example. A release team proposes reusing an employee’s account because that employee already has access, then refers to the resulting credential as an “API key”. The playbook halts for two independent reasons. First, the official purpose of a workspace service account is to avoid reliance on an employee’s account for headless Codex workflows. Secondly, a Codex access token for a ChatGPT workspace service account is not an API Platform project key. Renaming the credential informally would obscure which administrators, policies and billing boundary apply.
The correction is procedural, not cosmetic. Record the employee-login proposal as rejected; restate the workload as one non-human workspace identity for release-note-linter; and send any actual API Platform requirement to the organisation’s separate project-identity process. Do not copy permissions from the employee as a shortcut. Do not create a hybrid record that labels one credential both a token and an API key.
Decision rule: use this playbook only when Codex is to operate as a ChatGPT workspace service account. If the workload genuinely calls an API Platform project, stop and use the project’s own administration process. If the workload requires a person’s interactive judgement, retain the personal identity for that human activity rather than disguising it as unattended CI. The trade-off is that a dedicated account requires explicit administration, but it avoids coupling job continuity to employment status or personal access.
Assign direct minimum access, not the creator’s access
A workspace service account does not inherit the permissions of the owner or administrator who creates it. OpenAI’s service-account documentation says to assign its access directly. Creation authority and runtime access are therefore separate decisions: an administrator may be authorised to create the identity without the resulting identity receiving that administrator’s workspace permissions.
For release-note-linter, prepare an access worksheet before provisioning. List each direct role, group, plugin and connection proposed for the service account. Beside each item, state the exact part of the read-only check that depends on it. “The creator already has this” is not a justification. “Might be useful later” is also insufficient because future work can be reviewed as a scope change when it becomes concrete.
- Inventory: enumerate the direct assignments the job would need; do not infer them from a human account.
- Map: connect every assignment to one step in the declared job purpose.
- Challenge: ask whether the check can complete without that assignment.
- Remove or defer: exclude anything lacking a current, job-specific dependency.
- Record: retain the approved list so later reviewers can distinguish intended access from drift.
This procedure does not assert that any particular role, group, plugin or connection exists or is entitled in the reader’s workspace. Those categories are inspection prompts derived from the service-account documentation, not a catalogue of guaranteed capabilities. Local policy may prohibit an otherwise plausible assignment.
Decision rule: approve an item only when the named CI check cannot perform its declared function without it and the workspace permits it. If removing an item merely reduces speculative convenience, remove it. Minimum direct access creates more deliberate setup work than cloning a person’s access, but it reduces unrelated authority and makes review intelligible. Consequential access decisions require human owner and administrator review rather than automated approval.
Pre-flight Gates Before a Token Exists
No token should exist while authority, entitlement, policy or workload boundaries remain unresolved. Pre-flight is a sequence of stop/go gates, not a request form that presumes approval. In particular, this playbook does not assume that a workspace plan includes service accounts or infer eligibility from some other Codex capability.
Gate 1: confirm owner or administrator authority
Documented fact, as of 6 October 2026: OpenAI states that only workspace owners and administrators can create service accounts. A team member who lacks that authority may prepare the charter and evidence, but cannot substitute their own account or treat inability to create the identity as a product failure.
Identify the human who will exercise owner or administrator authority and the human who owns the CI service. They may be the same person, but record both responsibilities separately. The service owner explains why release-note-linter exists and accepts operational accountability. The workspace owner or administrator verifies authority, policy and entitlement and decides whether provisioning may proceed.
Example procedure: the engineering lead submits the one-job charter and proposed access worksheet to a named workspace administrator. The administrator confirms their current authority through the organisation’s established administrative process. This playbook deliberately provides no invented console path. If the administrator cannot confirm authority, the status is “administrative access unresolved”, not “service accounts unavailable”.
Decision rule: proceed only when a currently authorised owner or administrator accepts the provisioning review. A manager’s approval, repository ownership or control of the CI system is not a substitute for workspace authority. Centralising creation with authorised people can lengthen lead time, but it preserves the documented control boundary.
Gate 2: verify pay-as-you-go entitlement
Documented fact, as of 6 October 2026: OpenAI’s specific service-account documentation says service accounts are available only on pay-as-you-go plans. Therefore, the authorised reviewer must verify the workspace’s current entitlement rather than predict access from an organisation name, another documentation page or a general plan label.
Record a dated confirmation from the owner or administrator. The confirmation should identify the workspace reviewed and state whether its current arrangement satisfies the documented pay-as-you-go requirement. It should not include payment credentials, billing secrets or screenshots containing sensitive information. If the reviewer cannot verify the entitlement, stop with “entitlement unconfirmed”. Do not translate uncertainty into either approval or a claim that the capability is absent.
For the fictional job, an acceptable ledger entry would say: “Authorised workspace administrator confirmed the applicable pay-as-you-go service-account prerequisite on the review date.” That is an example of evidence wording, not a claim about any real workspace.
Decision rule: go only after current pay-as-you-go entitlement and applicable local policy are affirmatively confirmed. Stop when entitlement is absent or unconfirmed. The trade-off is a potentially slower start, but proceeding on assumption risks designing a workflow around an identity the workspace cannot provision.
Gate 3: classify denials, missing access and delay correctly
Three observations require different responses. A policy denial means an authorised decision-maker has determined that the requested action is not permitted. Missing administrative access means the current reviewer cannot perform or verify the action; it says nothing conclusive about another authorised owner or administrator. A synchronisation delay means an approved change may not yet be observable after an update. None should be relabelled as generic “absence of evidence”.
- For a policy denial: record the policy decision, the requested scope and the decision-maker. Halt unless a human-led exception process exists and grants approval.
- For missing administrative access: route the request to a verified workspace owner or administrator. Do not retry through a personal account.
- For a later synchronisation delay: record when the approved change was made, what observation is pending and who will recheck it. Do not broaden access merely to make the symptom disappear.
For example, if the engineering lead cannot see a provisioning control, that is missing or unverified administrative access, not proof that the workspace lacks service accounts. If an administrator explicitly rejects the proposed plugin under local policy, that is a policy denial. If an approved direct assignment is not yet reflected when later inspected, treat it as a possible synchronisation delay until an authorised reviewer resolves the state. Similarly, an omitted attachment or missing log is incomplete evidence, not proof that an event did not occur.
Decision rule: stop on an explicit denial; escalate missing authority to an authorised person; and hold the workflow until the approved update becomes observable. Do not compensate for ambiguity by granting broader permissions or creating another credential. Waiting can delay CI adoption, but preserves a defensible distinction between policy, authority and system state.
Build the redacted evidence ledger
Create one ledger entry before provisioning. Keep it in the organisation’s approved governance system and include references rather than secrets. The ledger should let a reviewer reconstruct why the identity exists without exposing the credential or placing untrusted repository data into an administrative prompt.
| Ledger field | Example entry for release-note-linter |
|---|---|
| Named CI job | release-note-linter |
| Accountable human owner | Approved internal identity reference |
| Workspace authority reviewer | Approved owner or administrator reference |
| Entitlement confirmation | Dated pay-as-you-go confirmation; no billing secret |
| Purpose and mode | Read-only release-note validation |
| Repository boundary | Approved repository reference; no additional repositories |
| Trusted runner class | Organisation-controlled restricted runner reference |
| Direct access to inspect | Roles, groups, plugins and connections, each with justification |
| Token name | Approved descriptive name, recorded only after issuance |
| Scope | Codex scope to be confirmed during issuance |
| Expiry | Finite policy-allowed date, recorded after selection |
| Secret-store reference | SECRET_REFERENCE |
| Human approval | Owner and administrator decision, date and conditions |
The secret-store field must contain only a reference such as SECRET_REFERENCE, never the token value. OpenAI’s service-account documentation states that the full token appears only once. The later capture process must therefore be planned before issuance, but this foundation section does not describe retrieval, injection or rotation mechanics. Keep credentials out of documentation, prompts, logs, chat messages and source control.
Keep the token out of logs, prompts and incident narratives rather than assuming a later sharing mechanism will make it harmless; the discussion of limits of Codex snapshot secret redaction reinforces that read-only sharing and known-pattern redaction do not remove the need for a human review of sensitive paths, diffs and values.
Decision rule: do not provision when any mandatory ledger field is blank, ambiguous or supported only by a repository-controlled assertion. The administrative cost of maintaining the ledger is justified by the ability to distinguish approved purpose, direct access, expiry and secret location without copying the secret itself. Human review is mandatory where the record will support a consequential access decision.
Set the runner and repository exclusion boundary
The proposed runner must be trusted before temporary token use is considered in a later section. OpenAI’s access guidance says to store tokens in a secret manager and use trusted runners, and warns that public CI, forked pull requests and shared machines can expose tokens. A job-level environment is also unsuitable if repository-controlled code can read its secrets.
For release-note-linter, record that the eligible runner class is organisation-controlled and restricted to the approved workflow. Explicitly exclude public CI, fork-triggered execution, general shared machines and repository-controlled code paths that can inspect job secrets. Keep untrusted release-note content out of provisioning prompts; the administrator needs the access rationale, not arbitrary repository text.
Decision rule: if the team cannot demonstrate separation between the secret-bearing runtime and untrusted or contributor-controlled code, stop before token creation. A more isolated runner may require additional operational work, but using a convenient public or shared execution surface would violate the intended credential boundary. This decision does not certify the runner as secure; it only establishes the minimum eligibility condition for later testing.
Choose a finite lifetime within policy
OpenAI directs administrators to name the token, confirm the Codex scope and choose an expiration. Workspace policy can constrain the available expiry choices. The team should therefore propose a finite review horizon but must not promise an expiry option until the authorised administrator confirms what policy permits.
For the fictional job, the owner records a finite operational need and a review date tied to the release process. The administrator later selects an allowed expiration that does not exceed the approved need. If the policy-allowed expiry options do not include the proposed lifetime, the owner must accept the shorter compliant lifetime or revise the operational plan; the team must not seek an unofficial workaround.
Decision rule: approve only a finite, policy-allowed lifetime aligned with the job’s review horizon. A shorter lifetime increases renewal and continuity work; a longer lifetime reduces that workload but extends the period in which the credential must remain governed. The administrator and accountable owner must make that trade-off explicitly.
Human approval checkpoint
Immediately before provisioning, hold a recorded human checkpoint. The accountable owner confirms the one-job purpose, repository boundary and runner exclusions. The owner or administrator confirms current authority, pay-as-you-go entitlement, local policy, proposed direct minimum access, Codex scope and a finite permitted expiry. Both confirm that the ledger contains only SECRET_REFERENCE, not a credential.
The checkpoint has two valid outcomes: approved to provision under recorded conditions, or stopped pending named evidence or remediation. Silence, an automated ticket transition or a successful unrelated login is not approval. Any later creation, scope change, rotation, revocation, disablement or deletion also requires an accountable human owner or administrator gate; those lifecycle procedures belong to later sections.
Limitations: local workspace policy can restrict service-account access, direct assignments and available expiry choices. Entitlement confirmation does not override policy, and administrative authority does not guarantee that a requested scope will be allowed. A later missing log, omitted attachment, delayed secret update or denied action must be assessed as its own observation. None alone proves that evidence, access or capability never existed.
Provision Direct Access Without Creating a Secret Trail
Continue only after the human owner has approved the pre-flight record for the fictional release-note-linter job. That approval establishes authority to prepare the account; it does not authorise broader access, token issuance or workflow changes by implication. Before either of those actions, the workspace owner or administrator and the job’s human service owner should review the proposed access together and record a second, explicit sign-off.
The relevant distinction is between the service account’s direct access and the privileges of the person creating it. OpenAI’s service-account documentation states, Assign its access directly; it doesn’t inherit the creator’s permissions.
The practical consequence is that an administrator should construct access from the job’s declared needs rather than copying their own configuration. This procedure concerns a ChatGPT workspace service account, not an API Platform project identity or key.
Translate the approved job description into direct access
Start with the job’s declared operation and evaluate each access category separately. For release-note-linter, the proposed operation is to check a prepared release-note draft against an approved style instruction. The administrator should not infer that a release-related job needs every resource used by the release team.
- Roles: assign a workspace role only when an operation in the approved job record requires it. A management role held by the creator is not evidence that the service account needs management authority.
- Groups: add the account to a group only if that group is the approved mechanism for obtaining required access and all access conveyed by the group is suitable for this one job. If the group bundles unrelated capabilities, prefer narrower direct access where workspace policy permits it.
- Plugins: permit a plugin only when the named linting operation explicitly depends on it. A plugin available to employees is not automatically part of a headless job’s boundary.
- Connections: allow a connection only when the job must use that particular connected resource. If the release-note text can be supplied through the controlled job input, a separate connection should not be added merely for convenience.
The decision rule is necessity plus boundedness: approve an item only if the named job cannot perform its approved operation without it and the item does not introduce unrelated access. If either condition is uncertain, leave the item unassigned and return the question to the human service owner. The trade-off is operational convenience versus an auditable one-job boundary; a broad group may be easier to administer, but it can defeat the purpose of direct minimum access.
A suggested review worksheet could use the following fictional, redacted structure. This is an example of a governance record, not a product-generated report:
| Access category | Proposed item | Job-specific reason | Decision |
|---|---|---|---|
| Role | ROLE_REFERENCE |
Required for the approved Codex linting operation | Pending owner or administrator review |
| Group | GROUP_REFERENCE |
No demonstrated dependency in the one-job charter | Do not assign |
| Plugin | PLUGIN_REFERENCE |
No plugin is required to inspect the supplied draft | Do not assign |
| Connection | CONNECTION_REFERENCE |
Input is delivered through the controlled job boundary | Do not assign |
This worksheet should describe the intended state rather than claim that access has already been granted. Missing access, a policy denial and an omitted record are different observations. For example, an empty connection entry may mean that none was requested, that evidence was not attached or that the reviewer has not completed the check. It does not, by itself, establish that the account has no connections.
Before allowing the one-job identity to perform anything beyond its smoke test, define what the pipeline may retain and who interprets it; the companion playbook on read-only Codex exec evidence packets shows how repository and CI evidence can be kept separate from a human go/no-go decision, reinforcing that a successful token-authenticated run is not an approval to release.

Place a human gate immediately before issuance
Present the proposed account name, direct-access worksheet, token plan, runner boundary and human service owner to the workspace owner or administrator. The approver should confirm that the record still matches the previously approved release-note-linter purpose and that current workspace policy permits the proposed finite expiry. No token should be issued and no workflow configuration should be changed until that approval is recorded.
The approval record should distinguish four decisions: approval to create the service account; approval of its direct access; approval to issue one named Codex-scoped token; and approval to configure the trusted runner. Combining them into an unexplained “approved” status makes later review ambiguous. Scope changes also require a fresh human gate: the team should not treat an existing account as standing authority to add a group, plugin, connection or role.
A concise fictional approval block might read:
JOB_NAME: release-note-linter
SERVICE_ACCOUNT_NAME: release-note-linter-ci
HUMAN_SERVICE_OWNER: OWNER_REFERENCE
DIRECT_ACCESS_RECORD: ACCESS_RECORD_REFERENCE
TOKEN_NAME: release-note-linter-ci-01
TOKEN_SCOPE: Codex
EXPIRY: EXPIRY_REFERENCE
RUNNER_BOUNDARY: RUNNER_POLICY_REFERENCE
SECRET_DESTINATION: SECRET_REFERENCE
ISSUANCE_APPROVAL: APPROVAL_REFERENCE
WORKFLOW_CONFIGURATION_APPROVAL: APPROVAL_REFERENCE
The example field names are deliberate. The record must not contain the token, a screenshot of it, a command for retrieving it or a value resembling a credential. It should also exclude confidential repository content and other untrusted data. A reviewer needs the account, purpose, scope, expiry and references—not the secret or material intended for a later Codex prompt.
Issue one named, expiring Codex token
Once the approval gate passes, the owner or administrator may create the service account with the reviewed direct access and prepare one token for this job. OpenAI’s documented sequence is to Name the token, confirm the Codex scope, and choose an expiration.
Workspace policy can constrain the available expiry choices, so the recorded lifetime should be one that the current policy actually allows rather than a duration copied from another environment.
Use a name that ties the token to the job and its operational generation without embedding confidential information. In this example, release-note-linter-ci-01 is meaningful because it identifies the job and distinguishes this issuance from a later replacement. Avoid a generic label such as automation, which makes ownership and later review harder.
The decision rule for expiry is to choose a finite, policy-allowed period that the human owner can operate responsibly. A shorter lifetime limits how long the credential remains usable but increases replacement frequency and the risk of an update being delayed. A longer permitted lifetime reduces operational churn but extends the period requiring active oversight. The administrator should record the selected expiry and the planned review date without claiming that expiry alone controls every exposure path.
OpenAI’s service-account documentation gives the critical handling constraint:
“The full token appears only once.”
Therefore, arrange the approved secret-management capture process before issuance begins. The authorised operator should transfer the one-time value directly into the approved secret-management process, verify that the intended secret reference has been created, and then leave only the reference in the runbook. Do not paste the value into a ticket, chat message, build definition, shell history, document or source file. OpenAI’s access-token guidance also says to keep credentials out of logs, chat messages and source control.
This procedure does not imply that a secret manager prevents exposure. It provides a controlled reference and handling boundary; runner design, workflow code, logging and human practice still determine whether the token can be disclosed. If capture fails or the expected record does not appear, stop. Do not improvise by copying the value into a temporary note. A delayed secret update, a denied action and an omitted attachment must be recorded as different conditions and investigated separately.
After capture, the runbook entry should contain exactly the operational metadata needed to identify the credential, never its value:
SERVICE_ACCOUNT_NAME: release-note-linter-ci
TOKEN_NAME: release-note-linter-ci-01
TOKEN_SCOPE: Codex
EXPIRY: EXPIRY_REFERENCE
SECRET_REFERENCE: SECRET_REFERENCE
The acceptance rule is strict: the token name, Codex scope, finite expiry and approved SECRET_REFERENCE must all be present, while the token value must be absent. If the reference is missing, the job is not ready. If an attachment or log is missing, mark the evidence incomplete rather than concluding that capture never occurred. Any later rotation, revocation, disablement or deletion remains deferred to its separate human-approved lifecycle procedure.
Choose the Temporary-Runner Token Path
There are two documented credential contexts, and they should not be blended. For a shared or temporary trusted runner, OpenAI directs operators to use CODEX_ACCESS_TOKEN without saving a login. By contrast, codex login --with-access-token saves a local credential and is reserved for a trusted machine. “Shared or temporary” describes runner lifetime or use; it does not establish trust. The team must evaluate the boundary before selecting either path.
For this playbook, choose temporary environment injection only if the runner is controlled, excludes untrusted workloads and can prevent repository-controlled code from reading the credential. Public CI, forked pull requests and shared machines are excluded because OpenAI’s guidance warns that those contexts can expose tokens. A machine used by unrelated people or projects is not made suitable merely by calling it a runner.
Verify the CLI floor before exposing the secret
OpenAI states, Service-account access tokens require Codex CLI version
Check the installed version before the token enters the job environment:0.142.0 or later.
codex --version
A human reviewer or trusted bootstrap component should compare the reported version with 0.142.0. Continue only when it is that version or later and the installed binary is the one approved for the runner. If the version is older, unreadable or absent from the retained evidence, fail closed and correct the runner image without injecting the token. An omitted version log is incomplete evidence; it is not proof that the wrong version ran.
The trade-off is between validating the runner before secret exposure and trying to diagnose everything inside the credential-bearing step. Separate validation is preferable here: it can reveal an incompatible installation without making the token available. Keep the retained output to the version result and ordinary job metadata; do not attach environment dumps.
Inject temporarily without creating a saved login
For the approved runner, map SECRET_REFERENCE to the process environment variable CODEX_ACCESS_TOKEN only for the harmless smoke-test process. The mapping should occur through the trusted runner’s protected execution layer, outside repository-controlled scripts. Do not include credential retrieval syntax in the repository or runbook, and do not print, transform, inspect or relay the value.
A suggested boundary description is:
TRUSTED_RUNNER: RUNNER_REFERENCE
SECRET_INPUT: SECRET_REFERENCE
PROCESS_VARIABLE_NAME: CODEX_ACCESS_TOKEN
ALLOWED_PROCESS: CODEX_SMOKE_TEST_REFERENCE
PERSIST_LOCAL_LOGIN: false
REPOSITORY_CODE_CAN_READ_SECRET: false
LOG_ENVIRONMENT: false
This is an example of the intended contract, not evidence that a CI product enforces it. The implementation must be reviewed against the actual runner. The smoke-test prompt should be fixed, harmless and free of repository secrets, customer material, attachments and untrusted issue or pull-request text. Its purpose is limited to checking that the named service identity can invoke the intended Codex path; success does not prove broad security, correct access to every resource or absence of other configuration defects.
Do not use codex login --with-access-token on this temporary-runner path, because that command saves a local credential. A saved login is appropriate only for a trusted machine where persistence is deliberate, approved and managed. The temporary path instead gives one process access through CODEX_ACCESS_TOKEN and then removes that process environment when the step ends.
The decision rule is persistence: if the approved design requires no local credential after the process, use temporary environment injection on a trusted runner. If a trusted machine genuinely requires a saved local login, treat that as a different design and obtain explicit human approval. Do not use saved login as a workaround for unreliable secret injection or an untrusted runner.
Do not carry a credential procedure across product boundaries merely because both secrets run in CI: this separately dated guide to API Platform project-key rotation is useful for comparing lifecycle discipline, but its project keys must remain distinct from the ChatGPT-workspace Codex-scoped service-account token used here.
Run the negative reachability test before enabling the job
Test whether repository-controlled build code could read the job environment before supplying the real token. Use a harmless sentinel value associated only with a test variable—not the token, SECRET_REFERENCE or CODEX_ACCESS_TOKEN—and execute the same repository-controlled path that the proposed job would invoke. The test asks whether untrusted build logic can observe a protected process environment; it must not request or expose any credential.
TEST_VARIABLE: HARMLESS_SENTINEL_REFERENCE
TEST_PATH: REPOSITORY_CONTROLLED_BUILD_STEP
EXPECTED_RESULT: sentinel is not readable
REAL_SECRET_PRESENT: false
Suppose the negative test shows that a repository script can enumerate the job-level environment and detect the harmless sentinel. That is a boundary failure, not permission to pass the token to the script. The team must redesign the workflow so the trusted wrapper owns token injection and invokes only the fixed, reviewed Codex operation, while repository-controlled code runs without the credential. Repeat the sentinel test after redesign and obtain human sign-off before configuring the real secret.
Do not “solve” the failure by masking log output, renaming the variable, forwarding it through another variable or relying on contributors not to inspect the environment. Those measures leave repository-controlled code with credential reachability. Likewise, do not run the credential-bearing job for a public pipeline or forked pull request, and do not move it to a shared machine. Exclude those triggers and machines at the trusted boundary.
The final issuance-to-run checkpoint requires two humans in their defined roles: the owner or administrator confirms the account, direct access, token name, Codex scope and finite expiry; the human service owner confirms the trusted-runner design, successful harmless sentinel isolation test and fixed smoke-test input. Only then may an authorised execution layer resolve SECRET_REFERENCE into CODEX_ACCESS_TOKEN for the bounded process. Any absent approval, delayed secret update, denied policy action or missing test record pauses the workflow for its own reason; none should be silently treated as equivalent to another.
Run the Smallest Possible Headless Check
The first execution should answer one narrow question: can the trusted runner invoke Codex non-interactively, through the approved ChatGPT workspace service account, without modifying the checkout? It should not lint a production release, publish an artefact, contact another service or inspect the wider repository. For release-note-linter, use a synthetic fixture containing invented release-note text and a local, non-sensitive rule file. This separates identity-path verification from the real job’s correctness.
OpenAI’s non-interactive-mode documentation, reviewed on 6 October 2026, identifies codex exec as the interface for scripts such as CI jobs:
“Non-interactive mode lets you run Codex from scripts (for example, continuous integration (CI) jobs) without opening the interactive TUI.”
Here, terminal user interface (TUI)A text-based interactive interface that runs in a terminal. Open glossary entry is the interactive interface that Codex opens in a terminal; the quoted sentence is reproduced from the official Codex documentation.
The same documentation states:
“By default,
codex execruns in a read-only sandbox.”
That default establishes the starting control. A successful read-only invocation demonstrates that the approved identity path can reach the documented non-interactive interface for this harmless task. It does not demonstrate that repository writes, external publication, every plugin or connection, or any later policy decision will succeed.
Validate the runner before binding the secret
Perform checks that do not require a token first. The service-account documentation says that its access tokens require Codex CLI version 0.142.0 or later. Accordingly, inspect the installed version before making SECRET_REFERENCE available to the process. Parse the reported semantic version rather than relying on a substring match: for example, 0.142.0 passes the documented floor, whereas 0.141.9 does not.
The procedure is: confirm that the worker belongs to the approved trusted-runner pool; verify that the trigger is an allowed protected-branch, scheduled or manually approved event; reject fork-derived execution; inspect the CLI version; and only then request job-scoped binding of the existing secret reference. Stop before binding if any precondition is unknown. The decision rule is fail closed: uncertainty about the runner, trigger or version is a precondition failure, not a reason to expose the credential and “see what happens”.
For example, a version-floor record may retain the runner-pool identifier, the parsed CLI version, the comparison result and the workflow revision. It should not contain environment dumps, authentication headers or token material. A runner reporting an older version should produce a non-sensitive “version floor not met” result and end before the secret-binding stage.
OpenAI’s service-account guidance, as reviewed on 6 October 2026, says:
“On shared or temporary runners, use
CODEX_ACCESS_TOKENwithout saving a login.”
In this playbook, “shared or temporary” does not make an arbitrary multi-user machine acceptable. The runner must still satisfy the approved trust boundary. The practical distinction is between a temporary job-scoped environment on an approved runner and a saved local login that persists beyond the job. Use the former here. Exclude public CI workers, developers’ shared machines, forked pull requests and any repository-controlled process that can read job secrets.

Bind the reference only for the authorised process
After the preconditions pass, make the token available as CODEX_ACCESS_TOKEN only to the process tree that runs the smoke test. The CI control plane may resolve SECRET_REFERENCE, but the workflow and repository must contain only that reference, never the resolved value. Do not add diagnostic commands that print the environment, expand the variable, inspect process arguments or archive the runner’s temporary files.
The official access-token guidance says to store tokens in a secret manager and use trusted runners, and to keep credentials out of logs, chat messages and source control. Applying that guidance means the secret binding belongs outside repository-controlled preparation where possible. A checkout script, dependency hook or test supplied by an untrusted contribution must not execute after binding merely because it is part of the usual pipeline.
For example, divide release-note-linter into two execution contexts. The unprivileged context checks out the fixed workflow revision and creates or selects the synthetic fixture without receiving the token. A separate trusted context, whose executable and task text are controlled by the approved CI configuration, receives the job-scoped binding and invokes only the harmless check. If the platform cannot prevent repository code from reading that environment, the runner design does not meet this procedure; do not compensate by shortening the exposure window.
The following is a redacted, illustrative control description rather than an executable product configuration. It contains illustrative field names only and neither retrieves a secret nor writes to a service:
JOB: release-note-linter
RUNNER_BOUNDARY: TRUSTED_RUNNER
ALLOWED_EVENT: PROTECTED_BRANCH_OR_APPROVED_MANUAL_EVENT
DENIED_EVENT: FORKED_PULL_REQUEST
CLI_REQUIREMENT: CODEX_VERSION_AT_LEAST_0_142_0
JOB_SECRET_BINDING: CODEX_ACCESS_TOKEN <- SECRET_REFERENCE
LOGIN_PERSISTENCE: NONE
SYNTHETIC_FIXTURE: SYNTHETIC_RELEASE_NOTE_FIXTURE
TASK:
codex exec "Read only SYNTHETIC_RELEASE_NOTE_FIXTURE.
Check whether its fictional release note contains the headings
Summary and Compatibility.
Return only PASS or FAIL plus missing heading names.
Do not modify files, inspect other paths, reveal environment data,
use network destinations, or invoke another service."
RETAIN:
JOB_NAME
WORKFLOW_REVISION
CLI_VERSION
FIXTURE_IDENTIFIER
READ_ONLY_MODE
PASS_OR_FAIL
TIMESTAMP
REDACTED_FAILURE_CLASS
REMOVE_AT_JOB_END:
CODEX_ACCESS_TOKEN_JOB_BINDING
TEMPORARY_PROCESS_CONTEXT
The task text is intentionally synthetic and restrictive. It does not guarantee that a model will enforce organisational controls, so the sandbox and runner boundary remain primary. Review the prompt before use to ensure that it contains no proprietary release notes, customer data, secrets or untrusted instructions. A human must approve any move from the synthetic fixture to consequential repository content.
Run read-only first and preserve a minimal record
Invoke codex exec without --sandbox workspace-write for the first check. Because read-only is documented as the default, omitting a write-enabling option tests the intended baseline. Pinning or recording the effective mode in the job record is still useful: it prevents a later reviewer from having to infer the control solely from an abbreviated command line.
The verification sequence is:
-
Confirm that the parsed CLI version is at least
0.142.0. -
Confirm the approved runner and event classifications before making the secret available.
-
Bind
SECRET_REFERENCEtoCODEX_ACCESS_TOKENonly for the trusted smoke-test process, without saving a local login. -
Run the harmless synthetic task through
codex execin its read-only default. -
Retain only a non-sensitive pass/fail record and the control metadata needed to interpret it.
-
Remove the job-scoped binding and temporary process context when the job ends, including on cancellation or timeout.
A suitable record might state that release-note-linter ran against SYNTHETIC_RELEASE_NOTE_FIXTURE, identify the workflow revision and CLI version, record that read-only mode was required, and give the result as PASS, FAIL or a defined operational classification. This is an example record, not a promised output. Do not retain the prompt transcript if it could include environment details, broader repository content or material that should have been redacted.
The trade-off is diagnostic depth versus unnecessary disclosure. A complete raw log may appear easier to troubleshoot, but it can include unrelated paths, prompts or environment data. Prefer a short structured record and a redacted failure class. If deeper evidence is genuinely needed, a human owner should approve a bounded diagnostic rerun after reviewing what will be collected; the existing token should not be exposed to increasingly verbose commands by default.
After the harmless smoke test, keep any repository remediation workflow separate from the service-account token; the design patterns in least-privilege Codex CI remediation distinguish read-only Codex analysis from a distinct repository write-permitted job and human merge gate, so the CI design does not treat workspace authentication as repository-write authority.
Prove the Boundary with a Harmless Smoke Test
A positive smoke test and a negative permissions test answer different questions. The positive test asks whether the approved identity path can complete one harmless non-interactive task. The negative test asks whether the default execution leaves a synthetic fixture unchanged. Run both before considering write access. Neither test proves that the service account has appropriate access across the organisation, that every future workflow revision is safe or that access reviews are current.
Pair the positive check with an immutable-fixture test
Create the synthetic fixture before binding the secret and calculate a local digest or equivalent integrity marker without including sensitive data. Run the read-only codex exec task, then calculate the marker again after the credential context has been removed. The expected boundary result is equality: the fixture and surrounding test directory should be unchanged.
For example, the fixture could contain fictional headings and a deliberately omitted Compatibility heading. The expected logical response may therefore be FAIL: Compatibility, while the permissions test still passes because no file changed. This distinction matters: a linter-style task can correctly report a content failure while the read-only boundary behaves as intended. Do not collapse application outcome and control outcome into one green or red indicator.
The procedure should record at least two independent fields: TASK_RESULT for the synthetic release-note assessment and FIXTURE_UNCHANGED for the permissions check. A content failure with an unchanged fixture is not an authentication failure. Conversely, an apparently correct textual answer does not compensate for an unexpected file change. If the marker differs, stop the job, preserve only non-sensitive metadata and escalate to the human service owner; do not rerun with wider permissions.
The decision rule is strict: retain read-only operation if the real release-note-linter only needs to inspect content and return a judgement. Read-only is also the correct choice when downstream CI can consume the result without Codex editing a file. Convenience, fewer pipeline steps or a desire to “fix as well as lint” is not by itself sufficient justification for widening the sandbox.
Authorise workspace-write only for a documented edit
Use --sandbox workspace-write only where the job charter identifies a necessary file edit, its permitted path, the expected file type and the human reviewer of the resulting change. Local write permission is not authority to publish, merge, deploy or alter a real service. Workspace sandbox settings also do not override ChatGPT workspace policy, direct service-account access, operating-system permissions, repository protection or CI controls.
Before enabling write capability, require explicit approval from the human service owner and an authorised workspace owner or administrator under the organisation’s change process. The approval should identify the exact workflow revision and bounded path. A general approval for “the CI bot” is insufficient because it does not distinguish this task from later repository-controlled behaviour.
A suitable comparison uses two runs over disposable, synthetic copies. First, run the read-only negative test and require that the synthetic fixture remains unchanged. Second, only after approval, run a workspace-write example whose sole documented purpose is to create or amend a disposable output beneath a dedicated path such as SYNTHETIC_OUTPUT_PATH. Review the resulting diff and discard the workspace. This suggested method demonstrates the contrast between modes; it is not evidence that every path outside the example is inaccessible.
The decision test has four parts:
-
Necessity: the named job cannot meet its approved purpose by returning a result alone.
-
Specificity: the intended edit and allowed local path are documented in advance.
-
Reviewability: a human can inspect the complete non-sensitive diff before consequential use.
-
Containment: the runner is disposable or resettable, and the write does not imply publication or deployment authority.
If any part fails, remain read-only and redesign the pipeline so another controlled step applies the change. This adds an extra hand-off but preserves a useful separation: Codex proposes or reports, while an independently authorised mechanism performs the consequential action.
OpenAI’s non-interactive-mode documentation says, “Use danger-full-access only in a controlled environment.” For this playbook, that mode is never a routine remedy for sandbox errors. Consider it only on an isolated controlled runner after human authorisation, with a documented reason that cannot be satisfied by read-only or workspace-write. If the team cannot define the isolation boundary and post-run disposal procedure, the mode is not permitted.
Drill the forked-pull-request denial
The failure drill must prove that an untrusted trigger is denied before secret binding, not merely that the later command happens to fail. Create or simulate the event classification for a forked pull request without placing confidential content in the test. The job should select a no-secret path, emit a non-sensitive denial reason and end without starting the token-bearing process.
For example, the control record may state EVENT_CLASS=FORKED_PULL_REQUEST, SECRET_BINDING=WITHHELD and CODEX_EXEC=NOT_STARTED. These are illustrative labels rather than product interface names. The drill must not print the secret store’s contents or test whether the token variable is empty from repository-controlled code, because that would place the verification on the wrong side of the boundary.
The decision rule is based on provenance, not contributor reputation or the apparent harmlessness of a patch. If executable workflow content or repository code originates from a forked pull request, the token-bearing job does not run. A trusted maintainer who wants to assess the change must first move the relevant, reviewed revision into an approved context through the organisation’s normal process. Manual approval alone must not silently convert untrusted code into code allowed to read job secrets.
This drill trades convenience for credential isolation. Fork contributors may not receive the authenticated smoke-test result on their original event, but the service-account token remains outside that execution context. Do not weaken the rule by exposing the token briefly, masking its output or assuming that log redaction prevents code from transmitting it elsewhere.
Classify no-result conditions before escalation
“No result” is not one diagnosis. Treat unavailable access, a policy denial, delayed secret synchronisation, an omitted log attachment and authentic absence of evidence as separate observations. None alone proves that the service account lacks access, that a policy permits the action, or that the smoke test did or did not run.
- Unavailable access
-
The trusted process cannot use the approved identity path. Record the stage and non-sensitive error classification, then ask the human owner or administrator to verify current direct access and entitlement. Do not widen permissions automatically.
- Denied policy action
-
A known policy prevents the requested operation. Treat the denial as a control outcome, not as transient unreliability. The human owner decides whether the job must be redesigned or whether a separately authorised policy change is appropriate.
- Delayed secret update
-
The approved secret reference may not yet be available in the intended runner context. Record the expected reference version or change ticket without recording its value. Escalate rather than repeatedly rebinding or alternating credentials. This section does not begin token rotation.
- Omitted attachment or log
-
The execution record is incomplete because expected non-sensitive evidence was not retained or attached. That is an evidence-handling defect, not proof of execution failure. A human should decide whether a bounded rerun is necessary.
- Authentic absence of evidence
-
No approved record establishes that the test ran or what it returned. Report the conclusion precisely as “not established”. Do not convert it into “access absent”, “test passed” or “test failed”.
Blind retries are inappropriate because they can increase token exposure, overwrite useful state and blur the distinction between delayed configuration and genuine denial. Permit a retry only when the human service owner has identified a bounded, non-sensitive reason, confirmed that the same trusted-runner conditions still hold and specified what new evidence the rerun is expected to produce.
State exactly what the smoke test establishes
If the positive task completes and the negative test confirms an unchanged fixture, the evidence supports a narrow statement: at that time, the approved trusted runner used the configured service-account path to invoke codex exec for the synthetic task under the observed read-only boundary. The retained record may also establish that the CLI met the documented version floor and that the temporary job context was scheduled for removal.
It cannot prove overall system security, correct access across the workspace, effective future revocation, safe behaviour of later prompts, absence of undiscovered runner compromise, continued entitlement or compliance with every organisational policy. It also cannot substitute for periodic human access review. Local sandbox success does not enlarge direct service-account permissions, override workspace policy or authorise consequential decisions.
Therefore, use the smoke-test record as a release gate for this bounded CI integration only. Require human review before enabling writes, changing scope, responding to unexplained denials or adopting a different runner class. Keep the evidence ledger open for the later lifecycle stage, but do not create a replacement token, revoke the current token, disable the account or start the rotation sequence in this section.
Replace, Verify and Revoke on a Finite Clock
Rotation is a controlled change, not an automatic property of the release-note-linter service account. The team must put each expiry, approval gate, secret-reference change, verification result and revocation decision on an operational calendar. OpenAI’s service-account and access-token documentation, reviewed on 6 October 2026, gives the order: Rotate a token by creating a replacement, updating the workflow, verifying access, and revoking the old token
. The procedure below applies that documented order to one trusted CI runner without claiming that the workspace or CI system performs lifecycle management automatically.
Schedule replacement backwards from expiry
Start with the policy-allowed expiry of the active Codex token and work backwards. The accountable human service owner should choose dates for approval, replacement creation, secret-reference promotion, a harmless smoke test and old-token revocation. Leave enough overlap to investigate a failed replacement, but do not turn overlap into indefinite dual-token operation. OpenAI documents that a token should be named, confirmed for Codex scope and assigned an expiration; workspace policy can constrain the expiry choices.
A practical example calendar is:
- Fourteen days before expiry: the human owner reviews whether
release-note-linterstill requires the service account, direct access and current sandbox setting. - Ten days before expiry: an owner or administrator approves or rejects replacement creation. Creation remains controlled by an owner or administrator; the current pay-as-you-go entitlement and local policy must still be checked.
- Seven days before expiry: the approved administrator creates the replacement token, records its label and expiry, and places its value directly into the approved secret manager. The ledger receives only a reference such as
SECRET_REFERENCE, never the value. - Six days before expiry: the workflow is changed to the approved new secret-reference version, initially for a harmless smoke test on the trusted runner.
- After the defined success condition: the human owner signs off revocation of the old token. An authorised operator then revokes that one token and records the outcome.
- Before the replacement’s next review window: the owner schedules the next decision rather than relying on memory or an assumed automatic reminder.
The decision rule is: create enough bounded overlap to permit validation, but revoke the old token only after the approved success criterion is met. If the old token expires first, treat that as expiry, not as evidence that replacement access works. If policy permits too little overlap for the proposed procedure, escalate the timetable to the owner or administrator instead of extending validity informally.
Use a four-stage controlled handover
First, create the replacement. An owner or administrator must approve creation before an authorised person creates a separately named, Codex-scoped token with a finite expiry. OpenAI states that The full token appears only once
. Capture it into the approved secret manager without copying it into a ticket, chat message, source file, build log or lifecycle ledger. The replacement must retain only the direct access justified for release-note-linter; it must not acquire access merely because its creator has it.
Secondly, update the approved secret reference. Promote a new secret version rather than putting secret material into repository configuration. For example, the workflow’s controlled deployment configuration may move from SECRET_REFERENCE version 12 to SECRET_REFERENCE version 13. This is a reference change, not a credential disclosure. Repository-controlled code, public CI, forked pull requests and shared machines must not be able to read the job secret.
Thirdly, run the replacement smoke test. Bind the replacement only to the authorised process on the trusted temporary runner. OpenAI documents that service-account access tokens require Codex CLI version 0.142.0 or later and that temporary or shared runners should use CODEX_ACCESS_TOKEN without saving a login. “Shared” here does not override the trust requirement: exclude general-purpose shared machines, public runners and any environment where unrelated or repository-controlled code can inspect the job environment.
The suggested test should invoke the documented non-interactive codex exec path against a harmless, synthetic fixture containing no secrets or untrusted data. Keep the default read-only sandbox unless the approved test specifically requires an edit. A suitable example criterion is: the trusted runner uses the approved CLI version, resolves secret-reference version 13, starts the expected non-interactive operation, reads only the synthetic fixture, returns the owner-approved completion status and emits no credential material. This criterion is an example, not a product guarantee or a broad security test.
Fourthly, revoke the old token. Revocation follows—not precedes—the recorded success condition and a human approval gate. The service-account documentation distinguishes the one-token revocation action as permanently revoking that token. Before using it, the operator must confirm the old token label, the service account, the superseding secret-reference version and the approval record. Afterwards, record the time and observed result without retaining secret material.
Maintain a rotation ledger without storing credentials
The following fictional ledger illustrates the minimum operational record. Dates, labels and statuses are examples only; they are not reported deployment results. “Pending” deliberately avoids inventing a successful execution.
| Ledger field | Old token | Replacement token |
|---|---|---|
| Service account | release-note-linter-ci |
release-note-linter-ci |
| Token label | rnl-2026-q3 |
rnl-2026-q4 |
| Expiry | 31 October 2026, 18:00 Coordinated Universal Time (UTC)The internationally agreed standard for world time, used here to identify the time reference in timestamps and offsets. Open glossary entry | 31 January 2027, 18:00 UTC |
| Human owner approval | Previously approved; revocation approval pending replacement test | Approved for creation by accountable owner; approval record CHANGE_REFERENCE |
| Secret reference | SECRET_REFERENCE, version 12 |
SECRET_REFERENCE, version 13 |
| Smoke-test outcome | Prior known state; bounded by stated expiry | Pending harmless read-only test |
| Revocation state | Do not revoke until the approved replacement criterion passes | Not applicable during replacement verification |
The ledger must record labels and references, not token values. It should also identify who approved creation, who observed the test, which runner class was used and whether the workflow reference was subsequently promoted. A missing attachment or omitted log is a record-quality problem; it does not prove that a test failed or never ran. Conversely, a verbal assertion that a test ran is not a substitute for the evidence required by the local change process.
Exercise the failed-replacement path
A negative rotation drill should prove that the team can stop before revoking the known token. Consider an illustrative case in which secret-reference version 13 is selected, but the replacement test cannot start because the runner has Codex CLI 0.141.0. That observation identifies a version-floor mismatch against the documented requirement of 0.142.0 or later. It does not demonstrate a bad token, missing workspace entitlement or absent direct access.
A different illustrative failure is an access denial after the version check passes. Because a service account does not inherit its creator’s permissions, the operator should compare its approved direct access with the requirement for the named job. A denied policy action, missing access, delayed secret update and omitted test log are distinct observations. Do not “fix” an access denial by broadening roles or groups during the test. Any scope change requires separate owner or administrator approval and a new recorded justification.
For either failure, follow this procedure:
- Stop the replacement test and preserve a redacted record of the stage, time, runner identity and observed error class.
- Do not print the environment, secret value or other credentials while diagnosing the failure.
- Restore the workflow’s prior approved secret-reference version only if the old token remains within its finite validity and there is no reason to suspect exposure.
- Run only the minimum local check needed to confirm restoration of the prior known state. Do not describe restoration as validation of the replacement.
- Escalate the failed criterion to the accountable human owner. Version changes, direct-access changes and a revised expiry plan require the relevant human approval.
- Leave the old token active only for the bounded recovery interval. Do not revoke it until the replacement meets the approved test criterion or until the owner chooses a different controlled exit.
The trade-off is continuity versus exposure duration. A still-valid old token can preserve the named job while the replacement is corrected, but prolonged overlap leaves two usable credentials. Therefore, rollback is permitted only to the prior approved reference, only while its validity remains bounded and only when there is no suspected exposure. If those conditions are not met, stop the job and escalate rather than improvising another credential path.
Respond separately to suspected exposure
Suspected exposure changes the objective from orderly rotation to stopping use. Do not keep using a potentially exposed old token merely because the replacement smoke test has not passed. Pause the affected job, remove the suspect reference from use, notify the accountable human and obtain the required sign-off for revocation. Where the evidence identifies one token, use the documented one-token revocation action rather than disabling or deleting the entire service account by default.
Then assess the runner boundary: determine whether the job ran on a trusted runner, whether a public or forked workflow could execute, whether repository-controlled code could read job secrets, and whether logs or attachments omitted material needed for review. Record the suspected route, affected scope, relevant times, operator actions and observed outcomes. Do not promise that revocation automatically contains every consequence; it permanently revokes the selected token, but human review is still needed to assess the runner, workflow and retained records.
The decision rule is proportionality with an approval gate. Revoke one token when the concern is credibly limited to that credential. Consider account-level disablement when use must stop across all its active tokens. Do not use irreversible deletion merely as a faster incident response when disablement would preserve the identity for investigation. Consequential incident decisions require human review.
Retire the Identity with an Auditable Exit
Retirement begins when the named job is removed, transferred to a different approved design or no longer justifies direct workspace access. An unused account should not remain enabled simply because its tokens are thought to be dormant. However, inactivity, missing logs or a failed access attempt does not establish that every token is absent or unusable. The owner must inventory the identity, its direct access, its recorded token labels and its remaining workflow references before choosing disablement or deletion.
Choose disablement or deletion deliberately
OpenAI’s service-account documentation distinguishes the two account-level actions. Disabling an unused service account is reversible at the identity level; deletion can’t be undone
. The documentation also states that both actions revoke all active tokens. If a disabled account is later re-enabled, it needs new tokens. Therefore, neither option preserves a token for later reuse.
Choose disablement when there is an approved reason to preserve the identity record or a realistic, reviewed possibility of reactivation. Choose deletion only when the organisation has concluded that the identity itself is no longer required and accepts irreversibility. In either case, require owner or administrator approval immediately before the action. Earlier project approval is not enough if scope, evidence or ownership has since changed.
A practical retirement procedure is:
- Stop scheduled and event-driven invocations of
release-note-linter. - Confirm that no approved workflow still references
SECRET_REFERENCEor any version associated with the account. - Review the account’s direct roles, groups, plugins and connections against the one-job charter; do not infer the creator’s access.
- Record known token labels and expiries without attempting to recover or reproduce token values.
- Select disablement or deletion, document the reason and scope, and obtain explicit human owner or administrator sign-off.
- Perform the approved action and record its time and observed outcome. Both actions should be treated as revoking all active tokens, as documented by OpenAI.
- Remove obsolete secret references, runner bindings and operational calendar entries through the organisation’s approved change process.
- Have a second authorised reviewer verify that the record describes what was observed rather than what was merely expected.
For example, a fictional exit record could state: service account release-note-linter-ci; reason, “named CI job decommissioned”; scope, “account and all active tokens”; selected action, “disablement pending retention review”; approver, OWNER_REFERENCE; action time, “pending”; outcome, “not yet observed”. This sample shows the required fields without pretending that an action occurred. After execution, the operator should replace “pending” only with the actual observed state.
If later reactivation is approved, treat it as a new controlled release: re-check pay-as-you-go eligibility, local permissions, direct minimum access, runner trust, Codex scope and expiry. Create new tokens under owner or administrator control because re-enablement does not restore revoked tokens. Do not reconnect an old secret-reference version on the assumption that it becomes valid again.
Close the evidence trail
The final lifecycle record should join the original one-job charter to the retirement decision. At minimum, retain the service-account name, named CI job, human owner, direct-access scope, token labels and expiries, secret-reference versions, rotation approvals, smoke-test classifications, revocation events, retirement reason, action scope, timestamps and observed outcomes. Keep credentials, untrusted repository content and sensitive log payloads out of that record and out of prompts.
Record the named human owner, direct role review and each lifecycle change so that access can be challenged later; for the wider administrative evidence model, see workspace permission and Codex-policy audit evidence, which covers proving access, delegated group administration and audit evidence for workspace-level Codex configuration changes.
This governance connection should not overstate the evidence. A completed activity review can show that required records were inspected and discrepancies assigned; it is not equivalent to a security audit. A harmless smoke test shows only that the defined narrow criterion was met in the tested runner context. It does not establish comprehensive security, universal availability, future reliability or correctness for other jobs.
Apply a continuing review cadence
Until retirement is complete, review the account at each rotation boundary and whenever the job, runner or required access changes. The reviewer should check current plan eligibility, owner or administrator authority, local permissions, direct access, token expiry, approved secret-reference version and runner trust. Also confirm that temporary injection remains confined to the trusted process and that public CI, forked pull requests, shared machines and repository-controlled code cannot read the secret.
Use an event-driven review rather than waiting for the calendar when there is a suspected exposure, ownership change, denied policy action, runner-boundary change, delayed secret update or unexplained missing record. The decision rule is to pause consequential changes when evidence is incomplete, classify the observation, and obtain human review. Do not interpret missing access as proof that the account has no token, or an omitted attachment as proof that no test occurred.
The principal limitation is entitlement and policy variability. The OpenAI sources reviewed on 6 October 2026 state that service accounts are available only on pay-as-you-go plans and can be created only by workspace owners and administrators. Current workspace eligibility, expiry options and local permissions must therefore be verified at the time of each consequential action. This playbook supplies a controlled procedure; it does not guarantee that a particular workspace can perform it.
Access 40,000+ AI Prompts for ChatGPT, Claude & Codex — Free!
Subscribe to get instant access to our complete Notion Prompt Library — the largest curated collection of prompts for ChatGPT, Claude, OpenAI Codex, and other leading AI models. Optimized for real-world workflows across coding, research, content creation, and business.
Useful Links
- OpenAI service accounts documentation
- OpenAI non-interactive mode documentation
- OpenAI access tokens documentation
