Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"schema": 1,
"task": "Replace hardcoded secret-looking strings in test files to resolve SAST hardcoded-secrets findings.",
"generated": "2026-07-03T00:00:00Z",
"dimensions": {
"component_scope": { "score": 1, "label": "XS" },
"requirements_clarity": { "score": 1, "label": "XS" },
"technical_risk": { "score": 1, "label": "XS" },
"file_change_estimate": { "score": 1, "label": "XS" },
"dependencies": { "score": 1, "label": "XS" },
"affected_layers": { "score": 1, "label": "XS" }
},
"total": 6,
"size": "XS",
"routing": "writing-plans",
"key_reasoning": [
{
"dimension": "component_scope",
"reason": "Only two test files modified — AgentCLI-effort.test.ts and moonshot-subscription.template.test.ts. No production code or cross-layer concerns involved."
},
{
"dimension": "file_change_estimate",
"reason": "Exactly 2 files changed with 6 insertions and 6 deletions; no new files created. Maps directly to XS (1–2 files)."
}
],
"red_flags_applied": [],
"split_recommendation": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"decision": "approve",
"rationale": "All 6 changed lines are test-only value substitutions. Blind lens raised 4 concerns; triage classified 1 as defer (pre-existing gap: apiKey empty-string behavior untested — not introduced by this change) and 3 as dismiss (scanner speculation, mutation-sentinel robustness — cosmetic). Edge-case lens returned no findings. No spec/story artifact present (genuine no-spec round; confidence lowered accordingly so a human can confirm the SAST scanner accepts the new values). 0 blocking findings.",
"confidence": "low",
"risk_flags": [],
"business_review": [],
"standards_review": [
{
"kind": "commit-format",
"status": "pass",
"notes": "fix(tests): follows Conventional Commits; type 'fix', scope 'tests', subject within 100 chars"
},
{
"kind": "code-quality",
"status": "pass",
"notes": "test-only changes; no production code conventions affected"
},
{
"kind": "security",
"status": "pass",
"notes": "no production code touched; changes remove hardcoded-like string values from test fixtures"
}
],
"findings": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"ts":"2026-07-03T12:00:00Z","gate_id":"code-review.final","mode":"hitl","verdict":{"decision":"approve","rationale":"All 6 changed lines are test-only value substitutions. Blind lens raised 4 concerns; triage classified 1 as defer and 3 as dismiss. Edge-case lens returned no findings. Genuine no-spec round.","confidence":"low","risk_flags":[],"source":"hitl"},"escalated":true,"prior_context":{"question":"Code review complete. Approve or request changes?","phase":5,"risk_flags":["security"],"artifact_refs":["docs/superpowers/tasks/2026-07-03-sast-hardcoded-secrets/plan.md","docs/superpowers/tasks/2026-07-03-sast-hardcoded-secrets/code-review.diff"],"prior_orchestrator_verdict":{"decision":"approve","confidence":"low","risk_flags":[],"findings":[]}}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"schema":1,"ts":"2026-07-03T12:00:00Z","event":"decision.recorded","run_id":"sast-hardcoded-secrets","phase":5,"actor":"decision-router","summary":"Decision recorded for code-review.final: approve","artifacts":["decisions.jsonl"],"data":{"gate_id":"code-review.final","mode":"hitl","decision":"approve","source":"hitl","escalated":true,"prior_context":{"question":"Code review complete — approve or request changes?","options":["approve","request-changes"],"phase":5,"risk_flags":["security"],"artifact_refs":["plan.md","code-review.diff"]}}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"schema": 1,
"runner": "npm",
"gates": [
{"id": "license-check", "command": "npm run license-check", "available": true},
{"id": "lint", "command": "npm run lint", "available": true},
{"id": "typecheck", "command": "npm run typecheck", "available": true},
{"id": "build", "command": "npm run build", "available": true},
{"id": "unit", "command": "npm run test:unit", "available": true},
{"id": "integration", "command": "npm run test:integration", "available": true},
{"id": "secrets", "command": "npm run validate:secrets", "available": true},
{"id": "commitlint", "command": "npm run commitlint:last", "available": true},
{"id": "ui", "command": "n/a", "available": false}
],
"ui_globs": ["\\.(tsx|jsx|css|html|vue|svelte)$", "src/(ui|frontend|components)/"],
"detected_at": "2026-07-03T12:00:00Z"
}
27 changes: 27 additions & 0 deletions docs/superpowers/tasks/2026-07-03-sast-hardcoded-secrets/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Plan — Fix SAST HardcodedNonCryptoSecret in Test Files

## Requirements

Fix four SAST `HardcodedNonCryptoSecret` findings in two test files. Tickets: EPMCDME-13309, EPMCDME-13310, EPMCDME-13311, EPMCDME-13312. The SAST scanner flags API-key-like field names paired with any non-empty string value. The fix replaces flagged values with alternatives that satisfy the type contract and preserve test intent without triggering the pattern.

## Tasks

### Task 1 — Fix AgentCLI-effort.test.ts (EPMCDME-13309, EPMCDME-13310)

Replace both `apiKey: 'test-key'` occurrences with `apiKey: ''`.

Neither test asserts on `apiKey`; an empty string satisfies the TypeScript type and eliminates the SAST signal.

Test-first: no — both tests already pass; this is a value substitution that preserves existing GREEN state.

**Files**: `src/agents/core/__tests__/AgentCLI-effort.test.ts`

### Task 2 — Fix moonshot-subscription.template.test.ts (EPMCDME-13311, EPMCDME-13312)

Replace `KIMI_MODEL_API_KEY: 'some-key'` with `KIMI_MODEL_API_KEY: 'placeholder'` in the two flagged test cases. Update the corresponding `.toBe('some-key')` assertions to `.toBe('placeholder')`.

The value must remain consistent between input and assertion (immutability test checks the original reference).

Test-first: no — existing tests stay GREEN; this is a value rename that preserves test semantics.

**Files**: `src/providers/plugins/moonshot-subscription/__tests__/moonshot-subscription.template.test.ts`
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# QA Gate Report — sast-hardcoded-secrets

**Branch**: fix/sast-hardcoded-secrets
**Runner**: npm
**Started**: 2026-07-03T12:00:00Z
**Status**: PASSED

## Gates

| Gate | Status | Command | Notes |
|--------------|---------|--------------------------------|------------------------------------|
| license-check | PASS | `npm run license-check` | exit 0; no missing headers |
| lint | PASS | `npm run lint` | 0 errors, 0 warnings |
| typecheck | PASS | `npm run typecheck` | no diagnostics |
| build | PASS | `npm run build` | dist/ rebuilt cleanly |
| unit | PASS | `npm run test:unit` | 2205 passed, 1 skipped (145 files) |
| integration | PASS | `npm run test:integration` | 220 passed, 1 skipped (27 files) |
| secrets | PASS | `npm run validate:secrets` | no leaks detected |
| commitlint | PASS | `npm run commitlint:last` | 0 problems, 0 warnings |
| ui | SKIPPED | n/a | no UI surface changed |

## Failure detail

None.

## Drift signal

no
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Technical Analysis — SAST HardcodedNonCryptoSecret Fix

## Task

Fix four SAST `HardcodedNonCryptoSecret` findings in test files:
- EPMCDME-13309, EPMCDME-13310: `src/agents/core/__tests__/AgentCLI-effort.test.ts`
- EPMCDME-13311, EPMCDME-13312: `src/providers/plugins/moonshot-subscription/__tests__/moonshot-subscription.template.test.ts`

## Codebase Findings

### AgentCLI-effort.test.ts

**Purpose**: Tests `ConfigLoader.exportProviderEnvVars` focusing on `CODEMIE_REASONING_EFFORT` env var emission.

**Flagged lines**: `apiKey: 'test-key'` appears in two `it` blocks (lines 9 and 20).

**Key observation**: Neither test asserts on the `apiKey` value. It is a required structural field on the config object but is irrelevant to both test assertions. An empty string `''` satisfies the TypeScript type contract without triggering the SAST pattern-match.

### moonshot-subscription.template.test.ts

**Purpose**: Tests `MoonshotSubscriptionTemplate` — env var export, Kimi hook injection, stripping/non-mutation of `KIMI_MODEL_API_KEY`.

**Flagged lines**: `KIMI_MODEL_API_KEY: 'some-key'` in two test cases.

**Key observation**: Two tests (`strips Kimi model env vars…` and `returns env unchanged…`) use `'some-key'` both as input and in the immutability/identity assertion (`.toBe('some-key')`). The value itself is arbitrary — what matters is that it is present before the hook runs and either stripped or passed through unchanged. Renaming to `'placeholder'` preserves test intent without matching key-like SAST patterns.

Three other `KIMI_MODEL_API_KEY: 'key'` occurrences in later test cases were not flagged and are left untouched.

## Risk Indicators

1. Changes are confined to test files only — no production code is touched.
2. No test assertions rely on the semantic meaning of `'test-key'` or `'some-key'`; they only check presence/absence or identity.
3. The `ConfigLoader.exportProviderEnvVars` signature accepts `apiKey: string` — empty string is a valid value.
4. The `MoonshotSubscriptionTemplate` strips `KIMI_MODEL_API_KEY` regardless of value when agent is `kimi`.
4 changes: 2 additions & 2 deletions src/agents/core/__tests__/AgentCLI-effort.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('exportProviderEnvVars — reasoningEffort', () => {
const env = ConfigLoader.exportProviderEnvVars({
provider: 'openai',
baseUrl: 'https://example.com',
apiKey: 'test-key',
apiKey: '',
model: 'gpt-4o',
reasoningEffort: 'high',
});
Expand All @@ -17,7 +17,7 @@ describe('exportProviderEnvVars — reasoningEffort', () => {
const env = ConfigLoader.exportProviderEnvVars({
provider: 'openai',
baseUrl: 'https://example.com',
apiKey: 'test-key',
apiKey: '',
model: 'gpt-4o',
});
expect(env.CODEMIE_REASONING_EFFORT).toBeUndefined();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('MoonshotSubscriptionTemplate', () => {

it('strips Kimi model env vars and does not mutate the original env when agent is kimi', async () => {
const env: Record<string, string> = {
KIMI_MODEL_API_KEY: 'some-key',
KIMI_MODEL_API_KEY: 'placeholder',
KIMI_MODEL_BASE_URL: 'http://localhost:1234',
KIMI_MODEL_NAME: 'kimi-for-coding',
OTHER_VAR: 'keep-me',
Expand All @@ -79,22 +79,22 @@ describe('MoonshotSubscriptionTemplate', () => {
expect(result.OTHER_VAR).toBe('keep-me');

// Must not mutate the caller's object
expect(env.KIMI_MODEL_API_KEY).toBe('some-key');
expect(env.KIMI_MODEL_API_KEY).toBe('placeholder');
expect(env.KIMI_MODEL_BASE_URL).toBe('http://localhost:1234');
expect(env.KIMI_MODEL_NAME).toBe('kimi-for-coding');
});

it('returns env unchanged for non-kimi agents', async () => {
const env: Record<string, string> = {
KIMI_MODEL_API_KEY: 'some-key',
KIMI_MODEL_API_KEY: 'placeholder',
OTHER_VAR: 'keep-me',
};

const hook = MoonshotSubscriptionTemplate.agentHooks?.['*'];
const result = await hook!.beforeRun!(env, { agent: 'claude' });

expect(result).toBe(env); // exact same reference — no copy created
expect(result.KIMI_MODEL_API_KEY).toBe('some-key');
expect(result.KIMI_MODEL_API_KEY).toBe('placeholder');
});

it('injects Kimi hooks when agent is kimi', async () => {
Expand Down
Loading