Skip to content
Back to skills

Api Integration Test

ASecurity

Create, maintain, and run gated Go integration tests for internal APIs and service-to-service clients (HTTP/gRPC). Use for endpoint verification, contract checks with real runtime config, opt-in execution, timeout/retry safety, and integration failure triage in Go services.

  • 30 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
ai-agentsrustgoshellbashdockertestingdebugginggitapisecurity

Works with

  • cli
  • api

Security analysis

A100/100

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

Scanned September 19, 2026

npx -y skills add johnqtcg/awesome-skills --skill api-integration-test --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api Integration Test?

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

Security grade badge for Api Integration Test
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/johnqtcg-api-integration-test/badge)](https://www.skillsdirectory.com/skills/johnqtcg-api-integration-test)

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: api-integration-test
description: "Create, maintain, and run gated Go integration tests for internal APIs and service-to-service clients (HTTP/gRPC). Use for endpoint verification, contract checks with real runtime config, opt-in execution, timeout/retry safety, and integration failure triage in Go services."
allowed-tools: Read, Write, Grep, Glob, Bash(go test*), Bash(go build*), Bash(make test-api-integration*), Bash(bash scripts/run_integration.sh*)
---

# API Integration Test

## Goal

Build production-representative, opt-in integration tests for internal APIs with strict safety controls, reproducible execution, and clear failure diagnosis.

## When To Use

Trigger this skill when the user asks for:
- Internal API integration tests (HTTP or gRPC)
- Service-to-service adapter tests requiring real runtime config
- Internal endpoint contract verification against real responses
- Integration test failure triage or debugging

## Scope

Use this skill for:

1. Internal HTTP API integration tests.
2. Internal gRPC client/server integration tests.
3. Service-to-service adapter tests requiring real runtime config.
4. Internal endpoint contract verification against real responses.

Do not use this skill for:

1. Pure unit tests with heavy mocks — use `$unit-test`.
2. Full end-to-end browser journeys.
3. Third-party vendor API tests — use `$thirdparty-api-integration-test`.

## Mandatory Gates

Gates execute in strict serial order. Any gate failure blocks all subsequent steps.

```
1) Scope        2) Go Version   3) Config       4) Mode
   Validation ──→  Gate       ──→  Completeness ──→  Selection
   │               │               │                │
   out of scope?   read go.mod    Full/Scaffold/   auto-select
   → stop+redirect → adapt        Blocked?         Smoke/Std/Comp
                                   Blocked → STOP
        │               │               │                │
        5) Production   6) Execution    7) Reference
           Safety     ──→  Integrity  ──→  Loading
           │               │               │
           prod? env+host  actually ran?   load by trigger
           → t.Fatalf      → report        pattern
```

### 1) Scope Validation Gate

Confirm the task falls within this skill's scope:
- Internal HTTP or gRPC API → proceed
- Pure unit test → redirect to `$unit-test`, **STOP**
- Third-party vendor API → redirect to `$thirdparty-api-integration-test`, **STOP**
- Full end-to-end browser journey → out of scope, inform user, **STOP**

**Hard stop**: If the target is out of scope, the entire remaining workflow is skipped. Output only: (1) scope verdict, (2) recommended skill or approach, (3) reason. Do NOT generate test code, do NOT proceed to subsequent gates.

### 2) Go Version Gate

Read `go.mod` for the project's Go version. Adapt patterns:

| Feature | Minimum Go | Adaptation |
|---------|-----------|------------|
| `t.Setenv` | 1.17 | Below: use `os.Setenv` + `t.Cleanup`. **Panics under `t.Parallel()` on every Go version** (process-wide env) — never combine them |
| `context.WithTimeout` (no leak) | all | Always `defer cancel()` |
| Range var capture fix | 1.22 | Below 1.22: copy loop variable (`tt := tt`) in closures |
| `t.Chdir` | 1.24 | Added 1.24 (below: `os.Chdir` + `t.Cleanup`). Like `t.Setenv`, cannot combine with `t.Parallel()` — panics |

If `go.mod` is not found, state `Go version: unknown` and use the most conservative patterns.

### 3) Configuration Completeness Gate

Apply `references/common-integration-gate.md` and determine degradation level:

| Level | Condition | Action |
|-------|-----------|--------|
| **Full** | All env vars documented, service address known | Proceed to generate complete tests |
| **Scaffold** | Some env vars missing | Generate test with `t.Skip(...)` + `// TODO:` markers. State what is missing in output. |
| **Blocked** | Gate env var unknown or service address undetermined | **STOP.** Output only: variable checklist + example command + setup instructions. |

Never hardcode guessed endpoints, credentials, or identifiers to make tests look runnable.

### 4) Execution Mode Gate

Auto-select mode based on task signals, then state the selection in output:

| Signal | → Mode |
|--------|--------|
| User says "smoke", "connectivity check", "health check" | Smoke |
| First-time environment validation | Smoke |
| Single endpoint, read-only operation | Smoke |
| User says "full", "comprehensive", "release gate" | Comprehensive |
| Post-migration or new service onboarding | Comprehensive |
| ≥ 5 endpoints or security-sensitive API (auth/payment/PII) | Comprehensive |
| User says "review", "audit", "improve", "upgrade" existing tests | Standard (unless explicit mode requested) |
| Everything else | **Standard** (default) |

If the user explicitly requests a specific mode, use that mode regardless of signals.

### 5) Production Safety Gate

**Never trust `ENV` alone** — an endpoint can point at production while `ENV=dev`
(`ENV=dev API_BASE_URL=https://api.production.internal`). Validate the *resolved
target host*, not just the label:

- Refuse when `ENV` is `prod`/`production` **OR** the resolved base-URL host matches
  a production pattern (contains `prod`, `production`, `live`, or a production
  domain suffix your org uses), unless `INTEGRATION_ALLOW_PROD=1`.
- Parse the base URL and check the host against a **non-prod allowlist** (preferred)
  or a prod **denylist** before any call. Fail **closed**: `url.Parse` accepts
  relative refs (`api.production.internal` parses with no error but empty scheme/host;
  `prod-host:8080` gets scheme `prod-host`), so require an **absolute `http(s)` URL
  with a non-empty host** — treat anything else as prod. Checking only the parse error
  is a bypass.
- Require a **dedicated test tenant/account** (e.g. `TEST_TENANT_ID`); refuse a target
  whose tenant is not the designated test tenant.
- For destructive operations (DELETE, UPDATE, DROP), require `INTEGRATION_ALLOW_DESTRUCTIVE=1`
  **in addition**. **A destructive write against production is forbidden under EVERY flag
  combination** — `INTEGRATION_ALLOW_PROD=1` permits READ-only prod tests, never writes. So
  a prod target + `ALLOW_PROD=1` + `ALLOW_DESTRUCTIVE=1` must still `t.Fatalf`. Destructive
  ops **require `NONPROD_HOST_ALLOWLIST`** (fail closed on host — a substring denylist would
  pass `https://api.company.com`) AND a validated non-prod tenant before any destructive call.

**When the run gate is enabled, refusal is a hard failure (`t.Fatalf`), not a silent
`t.Skip`** — see §Skip vs Fail (CI Integrity).

### 6) Execution Integrity Gate

Never claim tests were executed unless they actually ran.

- If `go test -tags=integration` was not run, output:
  - `Not run`
  - reason (e.g., service unreachable, env vars missing)
  - exact command to reproduce
- Do not imply pass/fail for tests that did not execute.
- Never report PASS when tests were actually skipped.
- **A `(cached)` result is NOT evidence of execution.** `go test` prints `ok … (cached)`
  when it reuses a prior result without running the binary — so the live service was
  never contacted. Every real integration run MUST pass `-count=1`; if output shows
  `(cached)`, report it as "did not run this time" and re-run with `-count=1`.

### 7) Load References Selectively

Always load:
- `references/common-integration-gate.md` — before authoring or determining degradation level.
- `references/common-output-contract.md` — before reporting results.

Load on condition:
- `references/checklists.md` — **only when** authoring new tests or triaging failures.
  When you author or review test code you MUST then score it against that file's
  §Test Quality Checklist and report the verdict (output-contract field 10): any single
  **Critical** FAIL is an overall FAIL, Standard needs ≥4/5, Hygiene ≥3/4.
- `references/internal-api-patterns.md` — **only when** writing HTTP/gRPC test code (not for scope rejection or result reporting).
- `references/advanced-patterns.md` — **only when** Comprehensive mode, CI integration, httptest adapter tests, or test data lifecycle management.

## Skip vs Fail (CI Integrity)

`t.Skip` on a *misconfigured* run is a false green: `go test` exits 0 when every
test skips, so a CI job that lost its config — or points at the wrong place —
passes silently. Distinguish **not requested** from **requested but broken**:

| Situation | Behavior | Why |
|-----------|----------|-----|
| Run gate unset (`INTERNAL_API_INTEGRATION != 1`) | `t.Skip` | User did not ask to run — correct to skip |
| Gate set, a required runtime var missing/empty | `t.Fatalf` | Run requested but misconfigured; skipping false-greens CI |
| Gate set, target is production (by ENV or host) without `INTEGRATION_ALLOW_PROD=1` | `t.Fatalf` | Loud refusal, before any call — a prod target you didn't authorize is a dangerous mistake, not a quiet skip |
| Gate set, destructive op without `INTEGRATION_ALLOW_DESTRUCTIVE=1` | `t.Skip` | A deliberate opt-in tier (like the run gate) — keep destructive tests in a separate CI job, NOT the base read-only gate |
| Scaffold test (a value could not be determined at authoring time) | `t.Skip` + `// TODO` | Incomplete by design — but it MUST be excluded from the official integration gate (separate build tag / not in the CI target) so a scaffold-only suite never reports green |

The line: **Skip = "not opted in / incomplete"** (run gate off, destructive not
enabled, scaffold); **Fatal = "opted in but broken or dangerous"** (config missing,
prod target unauthorized). A `t.Skip` that hides a misconfiguration is the bug.
Destructive and scaffold skips must live in CI jobs the base integration gate does
not depend on, so nothing false-greens.

## Execution Modes

### Smoke (connectivity check)
- Test 1 key endpoint per service — the simplest read-only call.
- Timeout: 5s. No retry.
- Assert only: connectivity + HTTP 200/gRPC OK + non-empty response.

### Standard (default)
- Cover primary endpoints: at least 1 success path + 1 expected-failure path per endpoint.
- Timeout: 15s. Max 1 retry for transient failures only.
- Assert both protocol-level and business-level outcomes.

### Comprehensive (full coverage)
- Cover all endpoints + error paths + boundary conditions.
- Timeout: 30s. Max 2 retries with bounded backoff.
- Include: concurrent request safety, large payload, pagination, rate limiting.

## Test Taxonomy

Three layers — only the last two are integration tests:

| Layer | Wiring | Integration? | Build tag |
|-------|--------|:---:|-----------|
| **Adapter / component test** | stub server (`httptest` with a fake handler) + real client | No — it is a unit test | none |
| **In-process integration test** | real handler + real dependencies (real DB/cache/queue) wired in-process, often via `httptest.Server` | Yes | `//go:build integration` |
| **System integration test** | client → a real, separately-deployed endpoint | Yes | `//go:build integration` |

The distinction is what sits *behind* the server: a **stub** handler exercises only
your client's parsing/transport (adapter test — no build tag, lives with unit tests);
a **real** handler with real dependencies is an in-process integration test. This
skill produces the two integration layers. A stub-`httptest` adapter test belongs in
`$unit-test`, not here.

## Required Test Pattern

1. Use file name `<domain>_integration_test.go` near the client/package under test.
2. Add build constraint at file top:
   - `//go:build integration`
   - `// +build integration`
3. Enforce explicit run gate env var (for example `INTERNAL_API_INTEGRATION=1`); when unset, `t.Skip` (the run was not requested).
4. Validate all required env vars at test start. When the gate is set but a required var is missing, `t.Fatalf` with an actionable message — do NOT `t.Skip` (see §Skip vs Fail (CI Integrity)).
5. Block production by ENV **and** by resolved host (never ENV alone):
   - refuse if `ENV` is `prod`/`production` OR the base-URL host matches a prod pattern, unless `INTEGRATION_ALLOW_PROD=1`; when the gate is set this refusal is `t.Fatalf`, not `t.Skip`.
   - require a dedicated test tenant/account and refuse non-test tenants.
6. Parse and validate env var payloads where needed (`strconv`, `strings.TrimSpace`, `url.Parse`, list parsing).
7. Build the client through the production code path against a real target. See §Test Taxonomy for what counts as integration vs an adapter/unit test — a stub `httptest` server is an adapter test, not an integration test.
8. Guard each external call with `context.WithTimeout`.
9. Use bounded retry policy only when justified:
   - default: no retry
   - if enabled: max 1-2 retries, bounded backoff, no infinite loop
10. Assert both:
    - protocol-level contract (HTTP status / gRPC code / required response fields)
    - business invariants (identity mapping, state transitions, key numeric constraints)
11. For expected failure paths, assert failure type/code explicitly (not only `require.Error`).
12. Keep tests idempotent and avoid destructive operations by default.
13. Define test data lifecycle explicitly:
    - setup source, idempotency key strategy, cleanup or safe reuse policy.

## Anti-Examples — DO NOT Write These Tests

1. **Mocking the client you are integrating against** — if you replace `http.Client` or the gRPC connection with a fake, it is a unit test, not an integration test. The entire point is to exercise the real transport path.

2. **Asserting on unstable response fields** — timestamps, request IDs, trace IDs, and randomly-ordered lists change per call. Assert on identity/contract fields, not volatile metadata.
   ```go
   // BAD
   require.Equal(t, "2026-03-08T12:00:00Z", resp.CreatedAt)
   // GOOD
   require.False(t, resp.CreatedAt.IsZero())
   ```

3. **Creating data with no cleanup strategy** — writing to a service that has no delete/archive API without documenting the data lifecycle leaves garbage that eventually breaks the test environment.

4. **Unbounded or unconditional retry loops** — retrying every error hides real failures. See `references/internal-api-patterns.md` §Retry/Timeout Policy Pattern for bounded retry with transient error classification.

5. **Testing internal implementation details** — asserting on the number of DB rows, internal cache state, or internal RPC call counts rather than the API's observable response contract.

6. **Running destructive operations without explicit opt-in** — `DELETE /users/:id` or `DROP TABLE` in a test without a separate env gate (e.g., `INTEGRATION_ALLOW_DESTRUCTIVE=1`) risks production data.

7. **Treating integration tests as performance benchmarks** — a single-call latency measurement has no statistical significance. Use dedicated load testing tools for performance.

8. **Ignoring context cancellation in retry loops** — always check `ctx.Done()` before sleep in retry loops. See `references/internal-api-patterns.md` §Retry/Timeout Policy Pattern.

## Go Implementation Baseline

```go
//go:build integration
// +build integration

func TestUserProfileIntegration(t *testing.T) {
    // Run gate OFF → skip: the user did not ask to run. Everything past this
    // point is "requested, so it must be correct" → t.Fatalf, never t.Skip
    // (see §Skip vs Fail (CI Integrity)).
    if os.Getenv("INTERNAL_API_INTEGRATION") != "1" {
        t.Skip("set INTERNAL_API_INTEGRATION=1 to run")
    }

    env := strings.ToLower(strings.TrimSpace(os.Getenv("ENV")))
    cfgDir := strings.TrimSpace(os.Getenv("CONFIG_DIR"))
    userID := strings.TrimSpace(os.Getenv("TEST_USER_ID"))
    tenant := strings.TrimSpace(os.Getenv("TEST_TENANT_ID"))
    baseURL := strings.TrimSpace(os.Getenv("API_BASE_URL"))
    if env == "" || cfgDir == "" || userID == "" || tenant == "" || baseURL == "" {
        // Gate enabled but misconfigured — FAIL, don't skip, or CI goes green blind.
        t.Fatalf("integration enabled but config incomplete: need ENV, CONFIG_DIR, TEST_USER_ID, TEST_TENANT_ID, API_BASE_URL")
    }

    // Production safety: refuse by ENV *or* resolved host, before any call.
    if isProdTarget(env, baseURL) && os.Getenv("INTEGRATION_ALLOW_PROD") != "1" {
        t.Fatalf("refuse production target (env=%q url=%q): set INTEGRATION_ALLOW_PROD=1 to override, or point at a non-prod endpoint", env, baseURL)
    }
    // A dedicated test tenant is mandatory (Safety Rules) — refuse a non-test tenant.
    assertTestTenant(t, tenant)

    cfg := config.MustLoad()
    client, err := NewInternalClient(cfg.InternalAPI)
    require.NoError(t, err)

    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    defer cancel()

    // Success path: protocol-level + business-level assertions
    resp, err := client.GetUserProfile(ctx, userID)
    require.NoError(t, err)
    require.NotNil(t, resp)
    require.Equal(t, http.StatusOK, resp.StatusCode)
    require.Equal(t, userID, resp.Body.UserID)
    require.NotEmpty(t, resp.Body.DisplayName)
}

func TestUserProfile_NotFound_Integration(t *testing.T) {
    if os.Getenv("INTERNAL_API_INTEGRATION") != "1" {
        t.Skip("set INTERNAL_API_INTEGRATION=1 to run")
    }
    // ... env gates same as above ...

    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    defer cancel()

    // Expected failure path: assert specific error, not just require.Error
    resp, err := client.GetUserProfile(ctx, "nonexistent-user-id-000")
    require.NoError(t, err) // HTTP call succeeded
    require.Equal(t, http.StatusNotFound, resp.StatusCode)
}

// isProdTarget refuses production by label OR resolved host, and FAILS CLOSED.
// url.Parse accepts relative refs: "api.production.internal" parses with NO error
// but an empty scheme and empty Hostname(), and "prod-host:8080" yields scheme
// "prod-host". Checking only err would let both bypass. So require an absolute
// http(s) URL with a non-empty host; anything else is treated as production.
// A non-prod host allowlist (NONPROD_HOST_ALLOWLIST) is more reliable than a
// substring denylist — prefer it when you can enumerate your test hosts.
func isProdTarget(env, rawURL string) bool {
    if env == "prod" || env == "production" {
        return true
    }
    u, err := url.Parse(rawURL)
    if err != nil || !u.IsAbs() || (u.Scheme != "http" && u.Scheme != "https") || u.Hostname() == "" {
        return true // fail closed
    }
    host := strings.ToLower(u.Hostname())
    if allow := strings.TrimSpace(os.Getenv("NONPROD_HOST_ALLOWLIST")); allow != "" {
        for _, h := range strings.Split(allow, ",") {
            if host == strings.ToLower(strings.TrimSpace(h)) {
                return false // explicitly allowed non-prod host
            }
        }
        return true // not on the allowlist → treat as prod
    }
    for _, bad := range []string{"prod", "production", "live"} { // fallback denylist
        if strings.Contains(host, bad) {
            return true
        }
    }
    return false
}

// assertTestTenant refuses a non-test tenant. TEST_TENANT_ALLOWLIST is REQUIRED
// (fail closed): unset → refuse; a tenant not on the list → refuse.
func assertTestTenant(t *testing.T, tenant string) {
    t.Helper()
    // Fail CLOSED: an allowlist of exact test-tenant IDs is REQUIRED. A denylist
    // ("reject names containing prod/live") is fail-OPEN — a real prod tenant
    // named "acme-main" or "tenant-001" would slip through. No allowlist → refuse.
    allow := strings.TrimSpace(os.Getenv("TEST_TENANT_ALLOWLIST"))
    if allow == "" {
        t.Fatalf("TEST_TENANT_ALLOWLIST is required: list the exact test tenant IDs permitted to run integration tests")
    }
    for _, id := range strings.Split(allow, ",") {
        if tenant == strings.TrimSpace(id) {
            return
        }
    }
    t.Fatalf("tenant %q not in TEST_TENANT_ALLOWLIST — refuse", tenant)
}

// assertDestructiveSafe gates destructive operations. A destructive WRITE is NEVER
// allowed against production under ANY flag combination (INTEGRATION_ALLOW_PROD
// permits READ-only prod tests, not writes). It fails CLOSED on the host — requiring
// an explicit NONPROD_HOST_ALLOWLIST, not the substring denylist (which would pass
// https://api.company.com) — and confirms the tenant is a designated test tenant.
func assertDestructiveSafe(t *testing.T, env, baseURL, tenant string) {
    t.Helper()
    if os.Getenv("INTEGRATION_ALLOW_DESTRUCTIVE") != "1" {
        t.Skip("destructive: set INTEGRATION_ALLOW_DESTRUCTIVE=1 to run")
    }
    if strings.TrimSpace(os.Getenv("NONPROD_HOST_ALLOWLIST")) == "" {
        t.Fatalf("destructive operations require NONPROD_HOST_ALLOWLIST (explicit non-prod hosts) — refuse without it")
    }
    if isProdTarget(env, baseURL) {
        t.Fatalf("destructive operations are forbidden against a production target, even with INTEGRATION_ALLOW_PROD=1")
    }
    assertTestTenant(t, tenant)
}
```

For Scaffold mode pattern (tests with `t.Skip` + `// TODO:` markers for missing config), see `references/common-integration-gate.md` §Scaffold Mode Example.

## Safety Rules

1. Never hardcode secrets, tokens, or private endpoints.
2. Use dedicated test tenant/account data.
3. Prefer read-only or reversible operations; explicitly gate destructive flows.
4. Refuse production environment by default.
5. Keep timeout bounded (typically 5-30s) and retries strictly limited.
6. Distinguish skip from fail (see §Skip vs Fail): `t.Skip` only when the run gate is off (or for a destructive/scaffold opt-in tier); when the gate is set but a prerequisite is missing or the target is prod-unauthorized, `t.Fatalf` with actionable instructions — never a silent skip.

## Execution Commands

Put the variables in a **gitignored** env file, then run the one-invocation wrapper:

```bash
cat > .integration.env <<'EOF'
INTERNAL_API_INTEGRATION=1
ENV=dev
API_BASE_URL=http://localhost:8080
CONFIG_DIR=/path/to/config
TEST_USER_ID=123
TEST_TENANT_ID=test-tenant-1
TEST_TENANT_ALLOWLIST=test-tenant-1
EOF

bash scripts/run_integration.sh .integration.env ./internal/pkg/client/user -timeout=30s   # Smoke
bash scripts/run_integration.sh .integration.env ./internal/pkg/client/user -timeout=120s  # Standard
bash scripts/run_integration.sh .integration.env ./internal/pkg/client/user -timeout=300s  # Comprehensive
```

**Why the wrapper rather than an inline `VAR=1 … go test …`** — two tool-runtime facts:

1. A strict `Bash(go test*)` allowlist matches only a command whose **first token** is
   `go test`. `INTERNAL_API_INTEGRATION=1 … go test …` starts with a variable assignment,
   so it does not match and stalls on a permission prompt.
2. Separate Bash invocations **do not carry env vars forward**, so "`export` … then
   `go test`" runs the test with none of the exported variables.

The env and the run therefore have to be one invocation. The wrapper **parses** the env
file as `KEY=VALUE` data — it never `source`s it, because sourcing executes any shell
hidden in a file that holds tenant IDs and tokens — appends `-count=1`, and refuses a file
that does not set the run gate (without it the whole suite skips and CI goes green blind).

The equivalent inline form is still correct when you are at a normal shell:

```bash
INTERNAL_API_INTEGRATION=1 ENV=dev API_BASE_URL=http://localhost:8080 \
  CONFIG_DIR=/path/to/config TEST_USER_ID=123 \
  TEST_TENANT_ID=test-tenant-1 TEST_TENANT_ALLOWLIST=test-tenant-1 \
  go test -tags=integration ./internal/pkg/client/user -run Integration -v -timeout=30s -count=1
```

`TEST_TENANT_ALLOWLIST` is mandatory (tenant validation is fail-closed — §Go
Implementation Baseline). A **destructive** run additionally needs
`INTEGRATION_ALLOW_DESTRUCTIVE=1` and `NONPROD_HOST_ALLOWLIST=<your test hosts>`
(destructive is fail-closed on host), and should live in a CI job separate from
the base read-only gate.

**`-count=1` is mandatory on EVERY real integration run, not just Comprehensive.**
Go caches a passing package's result keyed on the test binary + consulted env
vars + files — none of which include the external service. Without `-count=1` a
second run prints `ok … (cached)` and the test binary never executes, so a
service that changed (or broke) since the last run is never contacted. Treat a
`(cached)` line as **"did not run this time"** — never as evidence of a passing
integration against the live service.

## Output Contract

Use the shared output contract:
- `references/common-output-contract.md`
  Load always when reporting results.

## CI Integration

Check if the project already has a Makefile with integration test targets (e.g., `make test-api-integration`). If so, align with existing targets rather than adding new ones. Cross-reference `$go-makefile-writer` when Makefile targets should be added or repaired.

Integration tests in CI require service dependencies. For GitHub Actions service containers, Makefile targets, and Docker Compose patterns, see `references/advanced-patterns.md` §CI Execution Pattern.

Files in this skill

  • SKILL.md24.6 KB
  • references/advanced-patterns.md5.8 KB
  • references/checklists.md4.5 KB
  • references/common-integration-gate.md6.1 KB
  • references/common-output-contract.md2.1 KB
  • references/internal-api-patterns.md6.3 KB
  • scripts/run_integration.sh2.8 KB
  • scripts/run_regression.sh644 B
  • scripts/tests/COVERAGE.md9.9 KB
  • scripts/tests/golden/001_simple_http_get.json349 B
  • scripts/tests/golden/002_grpc_service.json324 B
  • scripts/tests/golden/003_retryable_endpoint.json298 B
  • scripts/tests/golden/004_production_safety.json260 B
  • scripts/tests/golden/005_missing_config_degradation.json275 B
  • scripts/tests/golden/006_ci_github_actions.json308 B
  • scripts/tests/golden/007_expected_failure_paths.json296 B
  • scripts/tests/golden/008_data_lifecycle.json221 B
  • scripts/tests/llm_eval/pure_normalizer/bad.md1.2 KB
  • scripts/tests/llm_eval/pure_normalizer/good.md1.4 KB
  • scripts/tests/llm_eval/pure_normalizer/meta.json1.3 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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.