Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
7016c95
test: require bounded scan and navigation errors
seonghobae Aug 12, 2026
682a694
fix: bound scan and navigation failure feedback
seonghobae Aug 13, 2026
069f84e
test: bind scan error feedback to operation scopes
seonghobae Aug 13, 2026
e9f08e6
fix: invalidate stale navigation when scanning
seonghobae Aug 13, 2026
8732705
test: cover stale post-scan result race
seonghobae Aug 13, 2026
c50fdd3
fix: guard stale post-scan result commits
seonghobae Aug 14, 2026
1a1587c
test: require bounded scan diagnostics
seonghobae Aug 15, 2026
669f71c
fix: retain bounded scan diagnostics
seonghobae Aug 15, 2026
1d00558
Merge branch 'main' into fix/scan-navigation-error-feedback-v1
opencode-agent[bot] Aug 22, 2026
ec2db50
Merge branch 'main' into fix/scan-navigation-error-feedback-v1
opencode-agent[bot] Aug 24, 2026
3ecfa31
chore: converge scan failure feedback on protected main
seonghobae Aug 27, 2026
052bb48
test: require canonical keyboard-accessible scan entry list
seonghobae Aug 27, 2026
1ef76e9
fix: make canonical scan entry list keyboard accessible
seonghobae Aug 27, 2026
42f0c97
fix(ui): make scan failures actionable and accessible
seonghobae Aug 29, 2026
56a8c68
Merge remote-tracking branch 'origin/main' into pr202
seonghobae Aug 29, 2026
5e2e54b
test: reject invalid negative paths-ignore filters
seonghobae Sep 3, 2026
47d16e0
fix(ci): use valid ordered path filters for contract docs
seonghobae Sep 3, 2026
439431a
test: reproduce paths-ignore parser blind spots
seonghobae Sep 3, 2026
80c8971
fix(test): inspect every paths-ignore list item
seonghobae Sep 3, 2026
bf8be64
merge: restack path-filter repair on release verifier
seonghobae Sep 3, 2026
5b005dd
merge: restack path-filter repair on release contract inheritance
seonghobae Sep 3, 2026
b5b1fe9
chore: restack scan feedback on canonical release owner
seonghobae Sep 3, 2026
190a9ee
test(ui): prove empty TopFiles result is reachable
seonghobae Sep 3, 2026
502c428
fix(ui): render empty TopFiles guidance after completed scans
seonghobae Sep 3, 2026
8633229
restack(ci): adopt current release foundation
seonghobae Sep 4, 2026
e0bf338
chore(stack): adopt bounded Vitest worker foundation
seonghobae Sep 4, 2026
9da857d
chore(stack): adopt current release foundation
seonghobae Sep 4, 2026
7440ceb
chore(stack): restack path-filter repair on release owner
seonghobae Sep 4, 2026
07c0d89
chore(stack): adopt current release foundation
seonghobae Sep 4, 2026
9e236eb
chore(stack): adopt exact release test repair
seonghobae Sep 4, 2026
83607d3
chore(stack): adopt exact release test repair
seonghobae Sep 4, 2026
7523243
chore: restack path-filter owner on current release foundation
seonghobae Sep 4, 2026
0369a80
chore: restack scan-navigation owner on current release foundation
seonghobae Sep 4, 2026
eb255b9
chore(stack): restack path-filter owner on current release foundation
seonghobae Sep 5, 2026
0602290
chore(stack): restack scan-navigation owner on current release founda…
seonghobae Sep 5, 2026
fe20596
test(ci): require canonical Windows agent-state regression
seonghobae Sep 6, 2026
29aaf64
fix(ci): own Windows agent-state regression in Test workflow
seonghobae Sep 6, 2026
f339ee4
fix(ci): run source-present macOS cache owner regressions
seonghobae Sep 6, 2026
dad7832
test: quote workflow command fixture correctly
seonghobae Sep 6, 2026
5b4e656
merge(ci): adopt current release/Test foundation
seonghobae Sep 9, 2026
13aa167
test(ci): require provider OAuth Windows process contract
seonghobae Sep 9, 2026
8b0e2b5
fix(ci): run provider OAuth process contract on Windows
seonghobae Sep 9, 2026
0e53be7
test(ci): require explicit agent-state skip evidence
seonghobae Sep 9, 2026
e17c2ad
fix(ci): make agent-state source absence explicit
seonghobae Sep 9, 2026
8a10edc
test(ci): make exact-head checkout contract lane-extensible
seonghobae Sep 9, 2026
02a95a6
chore: adopt current release foundation into Test owner
seonghobae Sep 9, 2026
f6c1d9a
fix(ci): isolate Ubuntu dependency refresh
seonghobae Sep 9, 2026
f5a7402
test(ci): lock Ubuntu apt isolation contract
seonghobae Sep 9, 2026
49623c6
Merge current release foundation into scan/navigation integration
seonghobae Sep 9, 2026
81e4195
Merge current foundation into scan/navigation owner
seonghobae Sep 9, 2026
bee9474
Merge shared Test owner into scan/navigation integration
seonghobae Sep 9, 2026
4d1a2e0
Merge current shared Test owner into scan/navigation owner
seonghobae Sep 9, 2026
dcb5385
test(ui): require scan to fail closed without a root
seonghobae Sep 10, 2026
f48a57d
fix(ui): fail closed scan control without a root
seonghobae Sep 10, 2026
74aa03c
Merge PR #376: disable scan when no root is available
seonghobae Sep 10, 2026
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
109 changes: 83 additions & 26 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,31 @@ name: Test
on:
push:
branches: [main]
paths-ignore:
- "docs/**"
- "*.md"
# Content-checked by contract tests (vitest + cargo test) — must still run CI.
- "!docs/doctoring/release-artifact-provenance.md"
- "!docs/doctoring/tauri-content-security-policy.md"
- "!docs/doctoring/model-artifact-integrity.md"
- "!docs/doctoring/model-load-handle-binding.md"
- "!docs/development/icloud-local-eviction-batch.md"
- "!docs/architecture/goals/cloud-offload-goal.json"
- "!CHANGELOG.md"
paths:
- "**"
- "!docs/**"
- "!*.md"
# GitHub supports re-inclusion only with ordered positive patterns under `paths`.
- "docs/doctoring/release-artifact-provenance.md"
- "docs/doctoring/tauri-content-security-policy.md"
- "docs/doctoring/model-artifact-integrity.md"
- "docs/doctoring/model-load-handle-binding.md"
- "docs/development/icloud-local-eviction-batch.md"
- "docs/architecture/goals/cloud-offload-goal.json"
- "CHANGELOG.md"
pull_request:
paths-ignore:
- "docs/**"
- "*.md"
# Content-checked by contract tests (vitest + cargo test) — must still run CI.
- "!docs/doctoring/release-artifact-provenance.md"
- "!docs/doctoring/tauri-content-security-policy.md"
- "!docs/doctoring/model-artifact-integrity.md"
- "!docs/doctoring/model-load-handle-binding.md"
- "!docs/development/icloud-local-eviction-batch.md"
- "!docs/architecture/goals/cloud-offload-goal.json"
- "!CHANGELOG.md"
paths:
- "**"
- "!docs/**"
- "!*.md"
# GitHub supports re-inclusion only with ordered positive patterns under `paths`.
- "docs/doctoring/release-artifact-provenance.md"
- "docs/doctoring/tauri-content-security-policy.md"
- "docs/doctoring/model-artifact-integrity.md"
- "docs/doctoring/model-load-handle-binding.md"
- "docs/development/icloud-local-eviction-batch.md"
- "docs/architecture/goals/cloud-offload-goal.json"
- "CHANGELOG.md"

permissions:
contents: read
Expand All @@ -49,7 +51,12 @@ jobs:
persist-credentials: false
- name: Install Tauri system deps
run: |
sudo apt-get update
for source_file in /etc/apt/sources.list.d/*; do
if [[ -f "$source_file" ]] && grep -q 'dl.google.com/linux/chrome' "$source_file"; then
sudo rm -f "$source_file"
fi
done
sudo apt-get -o Acquire::Retries=3 update
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev lsof
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
Expand Down Expand Up @@ -80,9 +87,34 @@ jobs:
- run: npm test
- run: npm run build

macos-cache-cleanup:
runs-on: macos-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
with:
workspaces: src-tauri
cache-targets: false
- name: macOS cache cleanup regressions when owner source is present
env:
TMPDIR: ${{ runner.temp }}
run: |
for test_name in cache_cleanup_corepack_scope cache_cleanup_cli_permanent_gradle generated_cache_staged_activity; do
if [[ -f "src-tauri/tests/${test_name}.rs" ]]; then
cargo test --manifest-path src-tauri/Cargo.toml --test "$test_name"
else
printf 'SKIP %s: owner test source absent; no runtime regression executed\n' "$test_name"
fi
done

windows-home-resolution:
runs-on: windows-latest
timeout-minutes: 10
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -95,6 +127,26 @@ jobs:
New-Item -ItemType Directory -Force target | Out-Null
rustc --edition=2021 --test src-tauri/tests/home_resolution_contract.rs -o target/home-resolution-contract.exe
& .\target\home-resolution-contract.exe
- name: Windows agent-state regression when owner source is present
shell: pwsh
run: |
if (Test-Path 'src-tauri/src/agent_state_guard.rs') {
rustc --edition=2021 --test src-tauri/src/agent_state_guard.rs -o target/agent-state-guard.exe
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\target\agent-state-guard.exe --nocapture
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
} else {
Write-Output 'SKIP agent_state_guard: owner source absent; no runtime regression executed'
}
- name: Windows provider OAuth process contract when owner source is present
shell: pwsh
run: |
if (Test-Path 'src-tauri/tests/provider_oauth_cli_process.rs') {
cargo test --manifest-path src-tauri/Cargo.toml --locked --features cloud-cli --test provider_oauth_cli_process
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
} else {
Write-Output 'SKIP provider_oauth_cli_process: owner source absent; no runtime regression executed'
}

llm-engine-build:
runs-on: ubuntu-latest
Expand All @@ -106,12 +158,17 @@ jobs:
persist-credentials: false
- name: Install build deps (llama.cpp native + tauri)
run: |
sudo apt-get update
for source_file in /etc/apt/sources.list.d/*; do
if [[ -f "$source_file" ]] && grep -q 'dl.google.com/linux/chrome' "$source_file"; then
sudo rm -f "$source_file"
fi
done
sudo apt-get -o Acquire::Retries=3 update
sudo apt-get install -y cmake clang libclang-dev libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
with:
workspaces: src-tauri
cache-targets: false
- name: Build with llm-engine (compiles real llama.cpp CPU + engine.rs FFI)
run: cargo test --manifest-path src-tauri/Cargo.toml --features llm-engine --lib --no-run
run: cargo test --manifest-path src-tauri/Cargo.toml --features llm-engine --lib --no-run
2 changes: 1 addition & 1 deletion src/lib/testWorkflowExactHeadContract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe("Test workflow checkout provenance", () => {
line.includes("- uses: actions/checkout@") ? [index] : [],
);

expect(checkoutIndexes).toHaveLength(3);
expect(checkoutIndexes.length).toBeGreaterThanOrEqual(4);
for (const checkoutIndex of checkoutIndexes) {
const stepIndent = lines[checkoutIndex].match(/^(\s*)/)?.[1] ?? "";
let endIndex = checkoutIndex + 1;
Expand Down
137 changes: 137 additions & 0 deletions src/lib/testWorkflowPathFilterContract.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { spawnSync } from "node:child_process";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";

const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
const workflow = readFileSync(resolve(repositoryRoot, ".github/workflows/test.yml"), "utf8");

function scalarValue(raw: string): string {
const value = raw.trim();
if (value.startsWith('"')) {
const end = value.indexOf('"', 1);
return end >= 0 ? value.slice(1, end) : value.slice(1);
}
if (value.startsWith("'")) {
const end = value.indexOf("'", 1);
return end >= 0 ? value.slice(1, end) : value.slice(1);
}
return value.split(/\s+#/, 1)[0].trim();
}

function negativePathsIgnoreEntries(source: string): string[] {
const negatives: string[] = [];
const lines = source.split(/\r?\n/);

for (let index = 0; index < lines.length; index += 1) {
const key = lines[index].match(/^(\s*)paths-ignore:\s*(.*)$/);
if (!key) continue;

const keyIndent = key[1].length;
const inline = key[2].trim();
if (inline) {
const listBody = inline.startsWith("[") && inline.endsWith("]")
? inline.slice(1, -1)
: inline;
for (const rawItem of listBody.split(",")) {
const value = scalarValue(rawItem);
if (value.startsWith("!")) negatives.push(value);
}
continue;
}

for (let cursor = index + 1; cursor < lines.length; cursor += 1) {
const line = lines[cursor];
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;

const indent = line.length - line.trimStart().length;
if (indent <= keyIndent) break;

const listItem = trimmed.match(/^-\s*(.+)$/);
if (!listItem) continue;
const value = scalarValue(listItem[1]);
if (value.startsWith("!")) negatives.push(value);
}
}

return negatives;
}

describe("test workflow path-filter contract", () => {
it("detects negative paths-ignore entries after comments and in inline lists", () => {
const fixtures = [
`pull_request:\n paths-ignore:\n - "docs/**"\n # contract exception\n - "!docs/example.md"\n`,
`push:\n paths-ignore: ["docs/**", "!docs/example.md"]\n`,
];

for (const fixture of fixtures) {
expect(negativePathsIgnoreEntries(fixture)).toContain("!docs/example.md");
}
});

it("does not put negative globs under paths-ignore", () => {
expect(negativePathsIgnoreEntries(workflow)).toEqual([]);
});

it("runs the Windows agent-state regression when that owner source is present", () => {
expect(workflow).toContain("Test-Path 'src-tauri/src/agent_state_guard.rs'");
expect(workflow).toContain(
"rustc --edition=2021 --test src-tauri/src/agent_state_guard.rs -o target/agent-state-guard.exe",
);
expect(workflow).toContain("& .\\target\\agent-state-guard.exe --nocapture");
});

it("reports absent Windows agent-state source without claiming runtime evidence", () => {
expect(workflow).toContain(
"SKIP agent_state_guard: owner source absent; no runtime regression executed",
);
});

it("runs the provider OAuth Windows process contract when that owner source is present", () => {
expect(workflow).toContain("Test-Path 'src-tauri/tests/provider_oauth_cli_process.rs'");
expect(workflow).toContain(
"cargo test --manifest-path src-tauri/Cargo.toml --locked --features cloud-cli --test provider_oauth_cli_process",
);
});

it("isolates Ubuntu dependency refresh from the hosted runner Chrome repository without weakening apt verification", () => {
expect(workflow.match(/grep -q 'dl\.google\.com\/linux\/chrome'/g)).toHaveLength(2);
expect(workflow.match(/apt-get -o Acquire::Retries=3 update/g)).toHaveLength(2);
expect(workflow).not.toContain("AllowInsecureRepositories");
expect(workflow).not.toContain("--allow-unauthenticated");
});
});

// Exercise the canonical shell admission without compiling or faking Rust test results.
it("macOS cache job executes present owner tests, reports absent source, and propagates failure", () => {
const job = workflow.split(" macos-cache-cleanup:\n")[1]?.split(" windows-home-resolution:")[0] ?? "";
expect(job).toContain("runs-on: macos-latest");
expect(job).toContain("ref: ${{ github.event.pull_request.head.sha || github.sha }}");
const script = job.match(/ run: \|\n([\s\S]*)/)?.[1].replace(/^ /gm, "") ?? "";
for (const target of ["cache_cleanup_corepack_scope", "cache_cleanup_cli_permanent_gradle", "generated_cache_staged_activity"]) {
expect(script).toContain(target);
}
const fixture = mkdtempSync(resolve(tmpdir(), "disksage-workflow-admission-"));
try {
const bin = resolve(fixture, "bin");
mkdirSync(bin);
const log = resolve(fixture, "cargo.log");
writeFileSync(resolve(bin, "cargo"), "#!/usr/bin/env bash\nprintf '%s\\n' \"$*\" >> \"$CARGO_LOG\"\nexit \"${CARGO_EXIT:-0}\"\n", { mode: 0o700 });
const env = { ...process.env, PATH: `${bin}:${process.env.PATH}`, CARGO_LOG: log };
const run = (extra = {}) => spawnSync("bash", ["-e", "-c", script], { cwd: fixture, env: { ...env, ...extra }, encoding: "utf8" });
const absent = run();
expect(absent.status).toBe(0);
expect(absent.stdout.match(/no runtime regression executed/g)).toHaveLength(3);
expect(existsSync(log)).toBe(false);
mkdirSync(resolve(fixture, "src-tauri/tests"), { recursive: true });
writeFileSync(resolve(fixture, "src-tauri/tests/generated_cache_staged_activity.rs"), "");
expect(run().status).toBe(0);
expect(readFileSync(log, "utf8")).toBe("test --manifest-path src-tauri/Cargo.toml --test generated_cache_staged_activity\n");
expect(run({ CARGO_EXIT: "7" }).status).toBe(7);
} finally {
rmSync(fixture, { recursive: true, force: true });
}
});
Loading