Skip to content

GitLab Service Account Standard — STD-GITLAB-SA-001

Purpose

Every autonomous agent role that performs source operations against GitLab — push, MR create/update/merge, CI trigger, authenticated API call, release or package publish, CODEOWNERS modification — MUST authenticate as a named machine identity: a GitLab Service Account or an appropriately-scoped CI token. Never as a human operator's personal account or session.

This standard defines the provisioning requirements, naming convention, scope rules, and audit obligations for Bluefly GitLab Service Accounts used by autonomous agents.

Scope

Applies to every agent with class: AGENT in the Agent Identity Registry that performs any of the operations listed under Purpose.

1. The Rule

AGENT_GITLAB_IDENTITY ≠ HUMAN_OPERATOR_IDENTITY

Every agent git commit, MR, CI trigger, and API call must carry
the agent's own machine identity, not a human operator's address,
not a personal-account session token.

Violation indicators:

  • Git author is a human operator's address on a commit authored by an autonomous agent session.
  • GITLAB_TOKEN in an agent environment resolves to a personal access token.
  • glab authenticated as a human account (flux423, bluefly) in an agent session.

R1 — Dedicated account, no borrowing

Each agent role MUST have exactly one GitLab service account. No two agents share an account. No agent uses a human's account.

2. Naming Convention (R2)

Pattern:  bluefly-<role-slug>-agent
Examples: bluefly-drupal-agent
          bluefly-blu-agent
          bluefly-mayor-agent
          bluefly-harbormaster-agent
          bluefly-sentinel-agent
          bluefly-refinery-agent

The bluefly- prefix signals machine identity; the -agent suffix signals autonomous operation; <role-slug> matches the gc_role in the Agent Identity Registry, lowercased. All service accounts are created at the group level (blueflyio/) with the minimum GitLab role required for the agent's actual operations.

3. Required Scope Per Role (R4 — least privilege)

Role Minimum GitLab Group Role Additional Scopes
bluefly-drupal-agent Developer api, write_repository scoped to Drupal rigs
bluefly-blu-agent Reporter read_api — routing/observation only
bluefly-sentinel-agent Reporter read_api — security observation
bluefly-refinery-agent Developer api, write_repository — governed delivery

Default scope for a role not listed above: read_repository + write_repository + create_mr. CI trigger, release, and package-publish scopes require explicit approval before they are added.

No service account is granted Owner or Maintainer at group level. Elevated operations go through CI pipelines with a scoped CI_JOB_TOKEN.

4. Secret Delivery (R3)

Service account tokens are delivered via 1Password Service Accounts using op:// references. See Authentication and Secrets Constitution for the full rotation and delivery contract. Token values are never:

  • written to files in the repository;
  • passed as shell arguments (process-table and wrapper-echo exposure);
  • printed in logs or session transcripts;
  • stored in city.toml or any tracked config file as plaintext;
  • placed in an environment file that 1Password does not manage.

See Authentication and Secrets Constitution §14–16 for the full rotation and delivery contract.

5. Git Config Per Agent Session (R6)

Git author metadata MUST reflect the agent's identity, not the human operator's. Each agent session configures:

git config user.name "Bluefly <Role> Agent"
git config user.email "bluefly-<role-slug>[email protected]"

These values MUST match the service account profile on GitLab. git config is set at worktree initialisation, never globally — a global machine identity bleeds into human sessions.

6. CODEOWNERS Entry (R5)

Every provisioned service account must have an entry in agent-identity-registry.yaml with gitlab_principal set to the actual GitLab username — not NOT_YET_PROVISIONED. Unprovisioned entries remain at NOT_YET_PROVISIONED until the service account is verified in production GitLab.

Every service account MUST be listed in the CODEOWNERS file of every repository it is authorised to merge into:

* @bluefly-<role-slug>-agent

The human reviewer remains in CODEOWNERS as final gatekeeper. Agent accounts are secondary approvers only, never sole gatekeeper.

7. Protected Branches (R8)

Service account tokens MUST operate under protected-branch rules that prevent force push on main and release/*. Enforced at the GitLab project level, not by convention.

8. Registry Obligation and Verification Before Use (R7)

Every provisioned service account must have an entry in agent-identity-registry.yaml with gitlab_principal set to the actual GitLab username. An entry remains provisioning_status: NOT_YET_PROVISIONED until all of the following are confirmed and recorded in the provisioning playbook:

  1. The GitLab account exists and its username matches §2.
  2. glab api /user with that account's token returns the correct username.
  3. A 1Password Service Account exists and delivers the token.
  4. Git config is set correctly in the agent's session template.
  5. At least one test push was made and the commit author matches §5.

9. Audit and Enforcement

CI gate validate-agent-identity (not yet implemented) validates that:

  • every AGENT and SERVICE class entry in the registry has gitlab_principal ≠ NOT_YET_PROVISIONED, or an explicit tracking note;
  • no human email appears as gitlab_principal;
  • the registry validates against agent-identity-registry.schema.json.

Until that gate exists, the registry is hand-audited on each MR that touches Engineering-Standard/catalog/. In addition:

  • gc lint (via blucity-packs) validates that agent session config includes a git_identity block before any formula.cook on a formula with contract = "gitlab".
  • ContractPlane ChangeRecipe validation enforces that the commit author matches the registered service account before MR creation.

10. Non-Compliance

An agent pushing under a human identity is a critical identity violation. On detection:

  1. The MR is closed without merge.
  2. A P0 bead is created: SECURITY: autonomous agent used human GitLab identity.
  3. The agent session is suspended pending provisioning.
  4. The incident is recorded in machine-identity-catalog.md with provisioning_status: VIOLATION.

11. Provisioning Procedure

See gitlab-service-account-provisioning-drupal.md for the step-by-step provisioning playbook, starting with bluefly-drupal-agent (PLY-GITLAB-SA-DRUPAL-001).


Related: Agent Identity Registry · Machine Identity Catalog · Identity Contract