Skip to content
Back to skills

Test Tenant Provisioner

ASecurity

MANUAL-ONLY; never auto-invoke. Provision and verify repeatable test tenants and users in a named NON-PRODUCTION environment for auth, row-level-security (RLS), integration and end-to-end (E2E) runs. Every created row carries a test marker and unmarked rows are never mutated; validate-only mode (the default) reports drift against the persona catalog, apply mode creates or repairs only marked tenants, users and memberships; credentials are referenced by environment-variable NAME only; capabili...

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 5, 2026
testinggotestinggitapidatabasesecurity

Works with

  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned October 5, 2026

npx -y skills add ModernNomad-98/Project-Aegis --skill test-tenant-provisioner --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Test Tenant Provisioner?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Test Tenant Provisioner
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/modernnomad-98-test-tenant-provisioner/badge)](https://www.skillsdirectory.com/skills/modernnomad-98-test-tenant-provisioner)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: test-tenant-provisioner
description: 'MANUAL-ONLY; never auto-invoke. Provision and verify repeatable test tenants and users in a named NON-PRODUCTION environment for auth, row-level-security (RLS), integration and end-to-end (E2E) runs. Every created row carries a test marker and unmarked rows are never mutated; validate-only mode (the default) reports drift against the persona catalog, apply mode creates or repairs only marked tenants, users and memberships; credentials are referenced by environment-variable NAME only; capability grants are backup-gated with an inline rollback; a static lint flags test automation that could reach production. WRITES to an environment, so manual invocation only. Use when test tenants or users are missing, drifted or hand-made, or runs fail on stale auth fixtures. Do NOT use to design the persona and data catalog (test-data-architect), write cross-tenant security tests (multi-tenant-security-tester), define the tenant model (tenant-modeler), or store or rotate secrets (secrets-identity-hardener).'
disable-model-invocation: true
---

# Test Tenant Provisioner

**Reading key:** RLS is row-level security (database rules that limit which
rows each tenant can read or write); E2E is end-to-end; CI is continuous
integration; API is application programming interface. A **tenant** is one
customer account in a multi-tenant product. A **persona** is a named test
user with a fixed tenant and role (for example "tenant A owner"). The
**persona catalog** is the written list of test tenants, personas, roles and
their stable identifiers. A **test marker** is a field or tag on a row that
says "this row was created for testing by this tool". A **slug** is a
tenant's short, unique text name, often used in its web address. Auth is
authentication, the sign-in check. **Drift** is any difference between the
catalog and what the environment actually holds. A **capability grant**
gives a user a role, permission or elevated flag. A **lint** is a static
check that reads files without running them. Playwright is a browser test
tool; URL is uniform resource locator.

## Purpose

Make the test accounts that auth, RLS, integration and E2E runs depend on
actually exist, in a named non-production environment, exactly as the persona
catalog describes them, and prove they still match. The deliverable is a
provisioning report. It always holds a drift table (missing, drifted,
orphaned, blocked) from a read-only validation. Only when a human explicitly
asks for apply mode and approves the exact plan does it also record the
marked rows created or repaired, each capability grant's backup reference
and rollback step, and a re-validation showing what still differs. It also reports a static lint of
test configuration that could point automation at production. Hand-made test
accounts drift silently; this skill replaces them with one repeatable,
checkable procedure.

*Provenance (history, not operative definitions):* built under owner decision
**D68** (2026-09-28) from roadmap row **#198**, as broadened by owner decision
**D10**; the [reconciliation
log](../../../docs/reconciliation/step-0-reconciliation-v4.md) carries the
entry. Those identifiers are recorded history, not requirements this skill
relies on — the procedure above is defined by this skill's own rules.

## Use When

- Use when: a human explicitly invokes this skill to check whether the test
  tenants, users, roles and memberships in a named test or staging
  environment still match the persona catalog (validate-only, the default).
- Use when: a human explicitly invokes it to create or repair missing or
  drifted test accounts in a named non-production environment (apply mode).
- Use when: auth, RLS, integration or E2E runs fail because a persona's
  account is missing, has the wrong role, or was hand-edited.
- Use when: test accounts were made by hand and need to be brought under a
  marker convention and a repeatable manifest.
- Use when: someone needs proof that test automation configuration cannot
  reach the production environment (the production-reach lint).
- Do NOT use when: the persona catalog, seeds or factories need DESIGNING —
  that is `test-data-architect`. This skill consumes its catalog; it never
  invents personas.
- Do NOT use when: the ask is to write cross-tenant or authorization negative
  TESTS — `multi-tenant-security-tester` *(manual-only)* owns the two-tenant
  fixture's required shape and the denial assertions; this skill only makes
  those accounts exist.
- Do NOT use when: the question is what a tenant IS, or how real customer
  tenants are provisioned in the product — `tenant-modeler`.
- Do NOT use when: credentials must be stored, issued or rotated —
  `secrets-identity-hardener` *(manual-only)*. This skill refers to them by
  variable name only.
- Do NOT use when: the work is browser auth-state files or Playwright
  fixtures that log these accounts in — `playwright-e2e-engineer`
  *(manual-only)*.
- Do NOT use when: the question is whether the RLS policies the accounts
  exercise are correct — `rls-policy-auditor`.
- Do NOT use when: the target is production, or a real customer tenant, for
  any reason. That is refused, not routed (see Stop Conditions).

## Inputs to Inspect

1. **The persona catalog** (`test-data-architect` output): tenants, personas,
   roles, memberships, capability grants and stable identifiers. Missing
   catalog → Stop Conditions.
2. **The target environment declaration:** its name, its host names, its
   database or project identifier, and the declared list of PRODUCTION hosts
   and identifiers to compare against. An environment is non-production only
   on positive evidence, never by its name alone.
3. **The tenant, user, role and membership model** in the product
   (`tenant-modeler` output or the schema): which tables or identity-provider
   objects hold each, and which API or admin path is the supported way to
   create them.
4. **The marker convention:** the field, tag or metadata key that marks a
   test-created row, and its value format. None yet → propose one (see
   [references/provisioning-manifest.md](references/provisioning-manifest.md))
   before any write.
5. **Credential references:** the environment-variable NAMES that hold each
   persona's password, token or key. Never read or print the values.
6. **The backup mechanism** for capability grants (for example an export of
   the current grant rows, a snapshot identifier, or an audit-log reference).
7. **Test automation configuration** for the lint: E2E base URLs, CI job
   environment blocks, seed-script connection settings, `.env.example` or
   environment templates, and test runner configuration files.
8. **The existing current state:** read-only listing of tenants, users,
   memberships and grants in the target environment, if a read path exists.

## Workflow

Explicit human invocation selects this execution-capable skill; it does not
expand the allowed target or activate Task-Authorized Local Implementation
(TALI). TALI is a separate route requiring its own classification and
activation under the [skill-generation standard](../../../docs/skill-generation-standard.md#5-least-privilege--side-effects).
Use applicable existing user grants without repeated consent. Before a
state-changing command, confirm its actual files, environment and effects fit
those grants; if authority is absent, propose the operation and obtain it
before proceeding.

1. **Confirm the catalog.** Load the persona catalog. If none exists, or it
   names personas without stable identifiers, stop and hand off to
   `test-data-architect`. Never invent a persona, role or tenant.
2. **Pin the environment.** Record the target environment's name, hosts,
   database or project identifier, and data origin (an environment restored
   from a production backup holds real customer rows, which stay untouched).
   Compare each against the declared
   production list. Classify it NON-PRODUCTION only when every identifier is
   positively different from production; anything unknown or shared is
   treated as production and the run stops.
3. **Build the desired-state manifest.** From the catalog, list every tenant,
   user, role, membership and capability grant with its stable identifier,
   its marker value and, for credentials, the environment-variable NAME that
   holds the secret. Format:
   [references/provisioning-manifest.md](references/provisioning-manifest.md).
4. **Validate (default mode, read-only).** Read the current state and compare
   it with the manifest. Classify every row as one of: OK; MISSING; DRIFTED
   (marked row with a wrong role, membership, tenant or grant); ORPHANED
   (marked row not in the catalog); BLOCKED (an UNMARKED row that collides
   with a catalog identity, such as the same email or tenant slug). Change
   nothing. If no read path exists, say so and mark the state UNVERIFIED;
   apply mode is then refused (see Stop Conditions).
5. **Run the production-reach lint (static, read-only).** Scan test
   configuration for any base URL, host, connection setting or default value
   that matches a declared production host or identifier, and for
   environment variables whose fallback default points at production. Report
   each hit with file and line. The lint compares declared values; it does
   not resolve names over the network unless that call is separately
   authorized.
6. **Stop here unless apply mode was explicitly requested.** Deliver the
   validation report. Apply mode needs all of: an explicit human request for
   apply, the named non-production environment from step 2, and approval of
   the exact change plan in step 7.
7. **Present the apply plan and obtain approval.** List each create or
   repair with its target row, its marker, and the supported path used (API,
   admin command or migration-safe seed). For each capability grant (a role,
   permission or elevated flag), show the backup reference that will be
   taken first and the inline rollback step beside it. BLOCKED rows are
   listed as untouched with the reason. Deleting ORPHANED marked rows is
   included only when the human asks for it. Wait for approval of this exact
   plan; a changed plan needs fresh approval.
8. **Apply to marked rows only, idempotently (running it again changes
   nothing more).** Create missing rows with the
   marker set at creation. Repair drifted rows only when the marker is
   present. Take each backup before its grant; if the backup fails, skip that
   grant and report it. Never change or delete an unmarked row. Refer to
   credentials by variable name only; if a value would appear in output,
   stop.
9. **Re-validate.** Run step 4 again and report residual drift. Apply is not
   done until the re-validation is shown.
10. **Report** in the Output Format, including what was not done and why.

When provisioning mechanisms are a real choice (for example the product's
admin API versus a database seed script), first define the terms; explain
each option's reason, setup and maintenance cost (or state that it is
unknown), and case-specific pros and cons; recommend one with a reason tied
to the user's context; then ask one question. If a deciding fact is missing,
ask only for that one fact first. A chosen option is not approval to write.

## Output Format

```
TEST TENANT PROVISIONING REPORT — <environment name>
Mode: validate-only | apply (plan approved: <quote + time>)
Environment evidence: <hosts / project id / data origin> vs production <list> → NON-PRODUCTION
Catalog: <source path + version>; manifest rows: <n tenants, n users, n memberships, n grants>
Marker convention: <field = value format>
Drift table:
  <row id> | <tenant/user/membership/grant> | OK | MISSING | DRIFTED (<what>) | ORPHANED | BLOCKED (unmarked collision)
Production-reach lint: <file:line — value — matched production identifier> | none found (<files scanned>)
Apply record (apply mode only):
  <row id> — created | repaired | skipped (<why>) — via <path>
  Grant <id> — backup <reference> — rollback: <exact inline step>
Credentials: referenced by variable name only — <VAR_NAME list>
Re-validation: <residual drift or "matches catalog">
Not done: <blocked rows, skipped grants, unverified reads, deletions not requested>
Handoffs: <test-data-architect | multi-tenant-security-tester | secrets-identity-hardener | playwright-e2e-engineer>
```

## Validation Checklist

- [ ] The persona catalog came from `test-data-architect` output; no persona,
      role or tenant was invented.
- [ ] The environment was classified non-production on positive evidence,
      and the evidence is in the report.
- [ ] Validate-only was the default; apply ran only after an explicit request
      and approval of the exact plan.
- [ ] Every created row carries the marker; no unmarked row was changed or
      deleted; BLOCKED rows are listed.
- [ ] Every capability grant has a backup reference and an inline rollback
      step, or is reported as skipped.
- [ ] No credential value appears anywhere in output, manifest or logs; only
      variable names.
- [ ] The production-reach lint ran and lists its scanned files.
- [ ] Re-validation after apply is shown; UNVERIFIED states are named.
- [ ] Any provisioning-mechanism choice explained terms, costs, pros and
      cons, and a recommendation before one question.

## Safety Rules

- Production is never a target. A request, a variable or a configuration
  default that points at production stops the run; no approval converts it.
- The marker is the only permission to touch a row. An unmarked row is
  someone else's data, even when its email or slug matches a persona.
- Credential values are never read into the conversation, written into the
  manifest, or echoed in logs. Missing variables are reported by name.
- Capability grants change who can do what; each one is backup-first with its
  rollback written beside it, so one step reverses it.
- Deletion is never implied by "repair". Removing marked orphans needs its
  own explicit request.

## Gotchas

- A staging database restored from a production backup contains real
  customer rows. They are unmarked, so the marker rule protects them, but
  it also means the environment evidence must check data origin, not only
  the host name.
- Identity providers often key users by email: a hand-made account with a
  persona's email is a BLOCKED collision, not a row to adopt silently.
- Creating users through raw database inserts can skip the identity
  provider, hooks and default memberships, producing accounts the product
  itself could never create. Prefer the product's supported admin path.
- A shared environment used by several teams may hold other teams' marked
  rows; scope the marker value (for example by suite or owner) so ORPHANED
  does not mean "someone else's".
- An E2E failure on a persona login can be the account (this skill) or the
  auth-state fixture (`playwright-e2e-engineer`); validate the account first
  so the two are not confused.
- `.env` defaults are the usual production-reach leak: a variable that falls
  back to the production URL when unset passes every local check.

## Stop Conditions

- The skill was selected automatically rather than explicitly invoked by the
  human: do not execute it. An agent may recommend the named manual skill.
- A write, Git/network operation, database command or test side effect exceeds
  the applicable human grant: stop that operation and obtain the missing scope.
  Existing authorized operations do not need the same permission again.
- The target is production, a real customer tenant, or an environment whose
  identifiers cannot be proven different from production → refuse the write
  and report why; do not offer a workaround. Synthetic accounts for
  production monitoring probes are designed by
  `synthetic-monitoring-architect`, not provisioned here.
- No persona catalog exists, or it lacks stable identifiers → stop and hand
  off to `test-data-architect`.
- The current state cannot be read (UNVERIFIED) → deliver the validate-only
  report and refuse apply mode until a read path exists; without a read, the
  marker on a row cannot be checked.
- Apply mode would change or delete an UNMARKED row → do not touch it; report
  it as BLOCKED and ask the human how the collision should be resolved.
- A capability grant's backup cannot be taken, or its rollback step cannot be
  written → skip that grant and report it; never grant without both.
- A credential value would be printed, stored or committed, or is missing →
  stop and report the variable name; custody goes to
  `secrets-identity-hardener` *(manual-only)*.
- The production-reach lint finds a hit → report it; do not apply against an
  environment whose test configuration can reach production until a human
  decides.
- The apply plan changed after approval → stop and obtain approval for the
  new plan. Creating, repairing, granting or deleting rows is the
  irreversible step this skill guards.

## Supporting Files

- [references/provisioning-manifest.md](references/provisioning-manifest.md)
  — desired-state manifest format, marker conventions, drift classes,
  capability-grant backup and rollback pattern, and production-reach lint
  rules.
- `evals/evals.json` — behavior cases: validate-only drift report, apply with
  backup and rollback, production refusal, unmarked-row block, missing
  catalog, UNVERIFIED state refusal, lint hit, credential refusal, and
  manual-only silence.
- `evals/trigger-evals.json` — discrimination against `test-data-architect`,
  `multi-tenant-security-tester`, `tenant-modeler`, `playwright-e2e-engineer`
  and `secrets-identity-hardener`.

Files in this skill

  • SKILL.md17.3 KB
  • evals/evals.json7.6 KB
  • evals/trigger-evals.json4.6 KB
  • references/provisioning-manifest.md4.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…