mikeparcewski

wicked-garden-qe-compliance-test-engineer

Regulatory-control specialist — SOC 2 / HIPAA / GDPR / PCI-DSS evidence collection. Reads a `controls:` list from the scenario frontmatter, executes a deterministic evidence-gathering command per control, and emits an auditor-ready `control-evidence.md` + a control-coverage CSV matrix. Verdict tags each control as satisfied / unsatisfied / out-of-scope. Use when: SOC2 readiness run, HIPAA control mapping, GDPR Article-30 record-of-processing, PCI-DSS scope audit, "prove we have evidence for CC6.1", control-walk-through generation. NOT THIS WHEN: regulatory analysis, sensitive-data-handling review, or remediation planning — use `wicked-garden-platform-compliance-officer` (advisor). THIS skill collects controls EVIDENCE against scenarios and records verdict rows; the officer analyses and advises.

mikeparcewski 9 2 Updated 1mo ago
GitHub

Install

npx skillscat add mikeparcewski/wicked-garden/wicked-garden-qe-compliance-test-engineer

Install via the SkillsCat registry.

SKILL.md

Compliance Test Engineer

You produce auditor-ready evidence for regulatory controls. Compliance
fails on the thing you didn't capture, not the thing you didn't do — so
every control the scenario lists gets a deterministic evidence artifact,
even if the artifact is "N/A: this workload is out of scope for PCI".
Your output is read by an auditor, not a developer. Be explicit.

Runtime

Script-backed steps use the wicked-garden launcher: wicked-garden run <plugin-root-relative path, e.g. scripts/…> [args]. It is on PATH after npm i -g wicked-garden; otherwise use npx wicked-garden run …; inside a wicked-crew run it is "$WICKED_GARDEN_ROOT/scripts/wicked-garden".
If none of these is available, or Python 3 is missing, skip the script-backed step, say so, and follow the manual alternative where one is given next to it — never invent the script's output.
Relative paths in this skill are relative to the directory that contains this SKILL.md.

1. Inputs

  • Scenario file path — frontmatter declares:
    • framework: one of soc2, hipaa, gdpr, pci-dss, or a comma-
      separated subset. Drives the control catalog.
    • controls: list of control ids exactly as written in the catalog
      (e.g. SOC2-CC6.1, HIPAA-164.308(a)(1), GDPR-Art-30,
      PCI-DSS-6.5.1).
    • scope: object with { systems[], data_classes[], regions[] } so
      the agent can flag out-of-scope controls without running them.
    • evidence_commands: optional override — maps a control id to a
      shell command. Without this the agent falls back to the builtin
      map shipped at lib/compliance/controls.json.
  • run_id — UUID of the current runs row; defines EVIDENCE_DIR.
  • .wicked-qe/config.json — detected_tooling must include
    at least one query/execution tool per control (e.g. aws, gcloud,
    kubectl, gh, opa) — control evidence that requires a missing
    tool is recorded as unsatisfied: tool-missing, NOT skipped.
  • .wicked-qe/evidence/<run_id>/context.md — optional domain
    rules like "production AWS account is 111-222" or "data class PHI
    only in eu-west-1".

2. Control catalog — shape

Each entry in lib/compliance/controls.json has:

{
  "id": "SOC2-CC6.1",
  "framework": "soc2",
  "title": "Logical and physical access controls",
  "evidence_command": "aws iam list-users --output json",
  "evidence_kind": "http-response",
  "scope_filters": ["systems", "regions"],
  "satisfied_if": {
    "kind": "jq-matches",
    "query": ".Users | all(.PasswordLastUsed != null)"
  }
}

The satisfied_if predicate is evaluated deterministically against the
captured evidence; it does not depend on LLM judgement.

3. Tool invocation

# Per-control evidence capture. `resolve-command.mjs` returns a JSON
# envelope `{ "cmd": "aws", "args": ["s3api", "get-bucket-policy", "--bucket", "..."] }`
# — NOT a shell string. `run-command.mjs` then spawns it without a shell
# (child_process.spawn with shell:false), so control templates cannot
# smuggle shell metacharacters or chained commands through scenario
# frontmatter. This is the CR-hardened replacement for the earlier
# `eval "${cmd}"` pattern flagged by gemini-code-assist.
for control in ${CONTROLS}; do
  envelope=$(node {WT_LIB}/compliance/resolve-command.mjs "${control}")
  out="${EVIDENCE_DIR}/controls/${control}.json"
  mkdir -p "$(dirname "${out}")"
  node {WT_LIB}/compliance/run-command.mjs --envelope="${envelope}" \
    > "${out}" 2> "${out%.json}.stderr" || true
  node {WT_LIB}/compliance/evaluate.mjs "${control}" "${out}" \
    > "${EVIDENCE_DIR}/controls/${control}.result.json"
done

Invariant enforced by run-command.mjs (follow-up ticket — not in this
PR): reject any envelope whose cmd is not in a per-framework allowlist
(SOC2: aws, gcloud, kubectl, jq, semgrep; HIPAA: same list plus
bandit; etc.). Unknown cmd -> ERR_CONTROL_TOOL_BLOCKED, no exec.

Worked examples per framework

# SOC2 CC6.1 — logical access: IAM users with MFA.
aws iam list-virtual-mfa-devices --output json \
  > "${EVIDENCE_DIR}/controls/SOC2-CC6.1.json"

# HIPAA 164.308(a)(1) — security management: who last ran a risk analysis.
gh api repos/:org/:repo/issues --jq '[.[] | select(.labels[].name=="risk-analysis")]' \
  > "${EVIDENCE_DIR}/controls/HIPAA-164.308.json"

# GDPR Art-30 — records of processing activities.
cat records/processing-activities.yaml \
  > "${EVIDENCE_DIR}/controls/GDPR-Art-30.yaml"

# PCI-DSS 6.5.1 — injection flaws: SAST evidence.
semgrep --config p/pci-dss --json src/ \
  > "${EVIDENCE_DIR}/controls/PCI-DSS-6.5.1.json"

4. Evidence output

Under .wicked-qe/evidence/<run_id>/:

evidence/<run_id>/
  controls/
    <CONTROL_ID>.json              # raw captured evidence
    <CONTROL_ID>.result.json       # satisfied_if evaluation
  control-evidence.md              # auditor-ready narrative
  control-coverage-matrix.csv      # columnar audit grid
  framework-summary.json           # per-framework roll-up
File manifest kind Required
controls/*.json http-response Yes, one per control
controls/*.result.json log Yes, one per control
control-evidence.md log Yes
control-coverage-matrix.csv log Yes
framework-summary.json misc Yes

control-evidence.md is structured as one section per control with
(a) control id + title, (b) evidence command executed, (c) captured
artefact path, (d) satisfied_if predicate + result, (e) scope applicability.

control-coverage-matrix.csv columns:
control_id,framework,title,status,evidence_path,captured_at,scope_applicable.
status ∈ { satisfied, unsatisfied, out-of-scope, tool-missing }.

5. DomainStore write

// verdict reflects whether every in-scope control is satisfied.
const unsatisfied = controls.filter(c => c.result === "unsatisfied");
const outOfScope  = controls.filter(c => c.result === "out-of-scope");
const satisfied   = controls.filter(c => c.result === "satisfied");
const verdict = unsatisfied.length === 0 ? "PASS" : "FAIL";

store.create("verdicts", {
  run_id: RUN_ID,
  verdict,
  reviewer: "wicked-garden-qe-compliance-test-engineer",
  reason: `framework=${framework} satisfied=${satisfied.length} unsatisfied=${unsatisfied.length} out_of_scope=${outOfScope.length} total=${controls.length}`,
  evidence_path: `evidence/${RUN_ID}/`,
  metadata: {
    controls_satisfied: satisfied.map(c => c.id),
    controls_unsatisfied: unsatisfied.map(c => c.id),
    controls_out_of_scope: outOfScope.map(c => c.id),
  },
});

// One open task per unsatisfied in-scope control.
for (const c of unsatisfied) {
  store.create("tasks", {
    project_id: PROJECT_ID,
    title: `Compliance remediation: ${c.id} (${c.title})`,
    status: "open",
    assignee_skill: "compliance-test-engineer:remediation",
    body: JSON.stringify({
      control_id: c.id, framework: c.framework,
      evidence_path: c.evidencePath,
      satisfied_if: c.satisfiedIf,
      observed: c.observed,
      remediation_hint: c.remediationHint,
    }),
  });
}

6. Failure modes

code meaning class
ERR_CONTROL_UNKNOWN scenario referenced a control id not in the catalog user
ERR_FRAMEWORK_UNSUPPORTED framework outside {soc2, hipaa, gdpr, pci-dss} user
ERR_SCOPE_MISSING frontmatter missing scope: block user
ERR_EVIDENCE_COMMAND_FAILED captured command exited non-zero; evidence empty system
ERR_TOOL_MISSING evidence command requires a tool not on PATH system
ERR_PREDICATE_ERROR satisfied_if predicate failed to evaluate (jq/rego) system

On ERR_TOOL_MISSING: record the affected control as unsatisfied: tool-missing and keep executing the rest — one missing tool must not
prevent the auditor from seeing every other control's evidence.

7. Non-negotiable rules

  • Every listed control produces an evidence file, even out-of-scope
    ones. The absence of an artefact is unexplainable to an auditor; an
    explicit "out-of-scope" file is auditable.
  • The satisfied_if predicate is deterministic. Never rely on LLM
    summarisation to decide whether a control passed; the predicate runs
    against captured JSON/YAML.
  • Scope is enforced, not advisory. If the scenario's scope excludes
    PCI-DSS, a PCI control id in controls: is out-of-scope, not an
    error — auditors need to see the trace of the decision.
  • CSV columns are stable. The matrix is consumed by auditor
    tooling. Do not add columns without a schema bump.
  • Never mark a control satisfied without a captured artefact.
    evidence_path is required; a satisfied control with no evidence
    path is a bug.

8. Output

## Compliance: {scenario.name}
framework: {framework}  controls: {count}
scope: systems={sysCount} data_classes={dcCount} regions={regCount}

controls:
  satisfied     : {n}/{total}
  unsatisfied   : {n}/{total}
  out-of-scope  : {n}/{total}
  tool-missing  : {n}/{total}

top unsatisfied:
  HIGH  SOC2-CC6.1  IAM users without MFA: 4
  MED   PCI-DSS-6.5.1  semgrep pci rules: 2 high-severity findings
  MED   HIPAA-164.308  no risk-analysis issue in last 365d

evidence: {EVIDENCE_DIR}/control-evidence.md  (auditor-ready)
matrix  : {EVIDENCE_DIR}/control-coverage-matrix.csv

VERDICT: PASS|FAIL
REVIEWER: wicked-garden-qe-compliance-test-engineer
RUN_ID: {RUN_ID}

Helper resolution ({WT_LIB})

{WT_LIB} is the plugin's own qe helper directory — the helper modules ship
in-catalog (scripts/qe/lib/, ported from the retired wicked-testing package
in Phase 6c). Resolve it (cross-platform):

WT_LIB="$(wicked-garden path scripts/qe/lib)"