Skip to content

Multi-team config ownership

VectorStep has no accounts and no self-service user management — see Security. That’s a deliberate design choice, not a gap, once you separate two different things that “who can do what” actually means here:

  • Who can author a pipeline or step. Low-risk, and — as of security.allow_shell_checks defaulting false and security.template_sandbox defaulting true — genuinely containable per team.
  • Who can mint a credential, and at what role. High-risk: an admin token is equivalent to shell on the host (see Threat model).

Conflating those two is what makes “no accounts” feel like a gap. Split them, and a plain git repo with CODEOWNERS covers the first one completely, while the second one staying centralized to one platform team is the correct answer, not a limitation to work around.

One platform (or “owning”) team runs the VectorStep instance. Other teams don’t log into it to manage their own access — they get handed a webhook-role token, same as Team attribution already describes: “onboarding a team” is synonymous with “issuing them a token.” What this page adds is where that token lives and who gets to change what, using the same git repo your CI/CD already deploys config from.

vectorstep-config/
config.yaml # server, database, auth, executors, notifications
pipelines/
platform/
10-self-monitoring.yaml
payments/
10-fraud-check.yaml
20-chargeback-alert.yaml
fulfillment/
10-shipping-delay.yaml
steps/
platform/
restart-service.yaml
payments/
verify-transaction.yaml
fulfillment/
check-carrier-status.yaml
CODEOWNERS

pipeline_config_dir and step_library_dir already load every *.yaml file in their directory (recursively is not required — one subfolder per team under each is enough) into one merged collection, so this layout needs no VectorStep code changes: point pipeline_config_dir: ./pipelines and step_library_dir: ./steps at the parent directories as normal, and file ownership is entirely a git-repo concern from there.

config.yaml itself — and therefore auth.tokens — has no equivalent multi-file mechanism; it’s loaded as exactly one file (CONFIG_PATH, see Deployment). That’s what makes it the natural place to draw the ownership line.

# Platform team owns the credential list and everything security-relevant.
/config.yaml @org/platform-team
# Each team reviews changes to its own pipelines and steps.
/pipelines/payments/ @org/payments-team
/steps/payments/ @org/payments-team
/pipelines/fulfillment/ @org/fulfillment-team
/steps/fulfillment/ @org/fulfillment-team
/pipelines/platform/ @org/platform-team
/steps/platform/ @org/platform-team

Pair this with branch protection requiring the matched CODEOWNERS review before merge. A payments engineer can now ship a new pipeline without a platform-team review on the pipeline logic itself — but cannot touch config.yaml, so cannot grant themselves a higher-role token, change security.allow_shell_checks, or add an admin credential. That boundary is what makes the “self-service” half of this safe to actually delegate: the directory split alone doesn’t guarantee it, the fact that allow_shell_checks/ template_sandbox live in the one file the team’s PR can’t touch does.

There’s no issuance endpoint — a token is a plain shared secret (see Team attribution). The process is a request, not a self-service action:

  1. A team opens an issue or PR touching only their own pipelines/<team>/ or steps/<team>/ path, tagging the platform team if they need a new webhook token to go with it.
  2. The platform team generates the value (openssl rand -hex 24) and adds the entry to auth.tokens in config.yaml — a PR only they can approve, per CODEOWNERS above.
  3. The raw value never appears in the git history. config.yaml references it as ${VECTORSTEP_WEBHOOK_TOKEN_PAYMENTS}; the platform team sets the actual value in whatever secrets store your deployment already reads ${ENV} substitutions from (a sealed secret, Vault, CI secrets — the mechanism is already documented in Deployment).
  4. The token value is delivered to the requesting team out of band — through the same secrets store, if they already have read access to their own secret, not pasted into the issue/PR that requested it.

Name each entry <team>-<role> (payments-webhook, payments-operator) — there’s no schema-level team field outside webhook-role tokens (see Security), so a consistent naming convention is what keeps the audit log (GET /audit, token name on every row) readable per team for operator/viewer/admin credentials.

No in-product way for a team to request or rotate their own token without the platform team’s involvement — that’s the point, not an oversight. If self-service token issuance for low-risk (webhook-only) credentials becomes worth building later, the natural extension is a directory-based loader for auth.tokens mirroring pipeline_config_dir’s existing pattern, with per-file validation rejecting anything above webhook/viewer role in a team-owned file. That doesn’t exist today — this page describes the git-review boundary you can use right now, not a roadmap item.