Skip to content
Merged
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
9 changes: 6 additions & 3 deletions deploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@ The only artifact paths exposed are the text-oriented report bundle files:
- `report_bundle/report/report.json`
- `report_bundle/report/run_summary.json`
- `report_bundle/poc/PoC.t.sol`
- `report_bundle/poc/LumosPoCBase.sol`
- `report_bundle/poc/Base.sol` (current PoC support contract)
- `report_bundle/poc/LumosPoCBase.sol` (legacy compatibility)
- `report_bundle/evidence/asset_deltas.json`
- `report_bundle/evidence/fund_flows.json`
- `report_bundle/visuals/asset_deltas.dot`
Expand Down Expand Up @@ -310,8 +311,10 @@ intentionally mount the output directory read-only to the MCP runtime.
## ECW internal export

Backlight can expose a dedicated ECW bundle without changing the operator API,
MCP tool list, worker queue, or the product artifact allowlist. The endpoint is
disabled unless a separate token is configured:
MCP tool list, or worker queue. The ECW endpoint uses a broader allowlist than
the narrow product artifact profile, which includes the current and legacy PoC
support contracts required by report bundles. The endpoint is disabled unless
a separate token is configured:

```bash
HELIOS_ECW_EXPORT_TOKEN=<separate-long-random-token>
Expand Down
3 changes: 2 additions & 1 deletion docs/results.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ Common artifact paths:
- `report_bundle/report/report.json`
- `report_bundle/report/run_summary.json`
- `report_bundle/poc/PoC.t.sol`
- `report_bundle/poc/LumosPoCBase.sol`
- `report_bundle/poc/Base.sol` (current PoC support contract)
- `report_bundle/poc/LumosPoCBase.sol` (legacy compatibility)
- `report_bundle/evidence/asset_deltas.json`
- `report_bundle/evidence/fund_flows.json`
- `report_bundle/visuals/asset_deltas.dot`
Expand Down
31 changes: 31 additions & 0 deletions internal/artifacts/ecw_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,37 @@ func TestECWReaderExposesDedicatedProfileWithoutChangingDefault(t *testing.T) {
}
}

// TestECWReaderServesRenamedPoCBaseContract guards the self-containment of the
// exported PoC project. The engine renamed the PoC base contract file from
// LumosPoCBase.sol to Base.sol (PoC.t.sol imports "./Base.sol"); the export
// allowlist must expose Base.sol at both PoC locations so the exported bundle
// compiles standalone instead of dropping the base file the PoC imports.
func TestECWReaderServesRenamedPoCBaseContract(t *testing.T) {
base := t.TempDir()
root := filepath.Join(base, "case_1")
writeArtifactFile(t, root, "report_bundle/poc/PoC.t.sol", "import \"./Base.sol\";\ncontract AttackTest is Base {}\n")
writeArtifactFile(t, root, "report_bundle/poc/Base.sol", "abstract contract Base {}\n")
writeArtifactFile(t, root, "artifacts/agent_poc/foundry/test/PoC.t.sol", "import \"./Base.sol\";\ncontract AttackTest is Base {}\n")
writeArtifactFile(t, root, "artifacts/agent_poc/foundry/test/Base.sol", "abstract contract Base {}\n")

reader, err := NewECWReader(base, 0)
if err != nil {
t.Fatal(err)
}
for _, rel := range []string{"report_bundle/poc/Base.sol", "artifacts/agent_poc/foundry/test/Base.sol"} {
if !slices.Contains(reader.AllowedPaths(), rel) {
t.Fatalf("ECW export profile missing renamed PoC base %q; exported PoC would not build", rel)
}
result, err := reader.Read(caseWithRoot(root), rel, 0)
if err != nil {
t.Fatalf("ECW Read(%q): %v", rel, err)
}
if result.Text != "abstract contract Base {}\n" {
t.Fatalf("unexpected PoC base content for %q: %+v", rel, result)
}
}
}

func writeArtifactFile(t *testing.T, root, rel, body string) {
t.Helper()
path := filepath.Join(root, rel)
Expand Down
3 changes: 3 additions & 0 deletions internal/artifacts/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var defaultArtifacts = []artifactSpec{
{PublicPath: "report_bundle/report/report.json", SourcePath: "report_bundle/report/report.json"},
{PublicPath: "report_bundle/report/run_summary.json", SourcePath: "report_bundle/report/run_summary.json"},
{PublicPath: "report_bundle/poc/PoC.t.sol", SourcePath: "report_bundle/poc/PoC.t.sol"},
{PublicPath: "report_bundle/poc/Base.sol", SourcePath: "report_bundle/poc/Base.sol"},
{PublicPath: "report_bundle/poc/LumosPoCBase.sol", SourcePath: "report_bundle/poc/LumosPoCBase.sol"},
{PublicPath: "report_bundle/evidence/asset_deltas.json", SourcePath: "report_bundle/evidence/asset_deltas.json"},
{PublicPath: "report_bundle/evidence/fund_flows.json", SourcePath: "report_bundle/evidence/fund_flows.json"},
Expand Down Expand Up @@ -62,6 +63,7 @@ var ecwArtifacts = []artifactSpec{
{PublicPath: "report_bundle/report/report.json", SourcePath: "report_bundle/report/report.json"},
{PublicPath: "report_bundle/report/run_summary.json", SourcePath: "report_bundle/report/run_summary.json"},
{PublicPath: "report_bundle/poc/PoC.t.sol", SourcePath: "report_bundle/poc/PoC.t.sol"},
{PublicPath: "report_bundle/poc/Base.sol", SourcePath: "report_bundle/poc/Base.sol"},
{PublicPath: "report_bundle/poc/LumosPoCBase.sol", SourcePath: "report_bundle/poc/LumosPoCBase.sol"},
{PublicPath: "report_bundle/evidence/asset_deltas.json", SourcePath: "report_bundle/evidence/asset_deltas.json"},
{PublicPath: "report_bundle/evidence/fund_flows.json", SourcePath: "report_bundle/evidence/fund_flows.json"},
Expand All @@ -82,6 +84,7 @@ var ecwArtifacts = []artifactSpec{
{PublicPath: "artifacts/agent_poc/summary.json", SourcePath: "artifacts/agent_poc/summary.json"},
{PublicPath: "artifacts/agent_poc/foundry/foundry.toml", SourcePath: "artifacts/agent_poc/foundry/foundry.toml"},
{PublicPath: "artifacts/agent_poc/foundry/test/PoC.t.sol", SourcePath: "artifacts/agent_poc/foundry/test/PoC.t.sol"},
{PublicPath: "artifacts/agent_poc/foundry/test/Base.sol", SourcePath: "artifacts/agent_poc/foundry/test/Base.sol"},
{PublicPath: "artifacts/agent_poc/foundry/test/LumosPoCBase.sol", SourcePath: "artifacts/agent_poc/foundry/test/LumosPoCBase.sol"},
{PublicPath: "artifacts/agent_poc/foundry/lib/forge-std/src/Test.sol", SourcePath: "artifacts/agent_poc/foundry/lib/forge-std/src/Test.sol"},
{PublicPath: "artifacts/poc_sketch/poc_sketch.sol", SourcePath: "artifacts/poc_sketch/poc_sketch.sol"},
Expand Down
10 changes: 10 additions & 0 deletions internal/artifacts/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func TestReaderExposesPrettyProductArtifactAliases(t *testing.T) {
if err := os.WriteFile(filepath.Join(root, "report_bundle", "poc", "LumosPoCBase.sol"), []byte("abstract contract LumosPoCBase {}\n"), 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(root, "report_bundle", "poc", "Base.sol"), []byte("abstract contract Base {}\n"), 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(root, "report_bundle", "evidence", "asset_deltas.json"), []byte(`[]`), 0o644); err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -151,6 +154,13 @@ func TestReaderExposesPrettyProductArtifactAliases(t *testing.T) {
if pocBase.Text != "abstract contract LumosPoCBase {}\n" {
t.Fatalf("unexpected PoC base: %+v", pocBase)
}
currentPoCBase, err := reader.Read(c, "report_bundle/poc/Base.sol", 0)
if err != nil {
t.Fatal(err)
}
if currentPoCBase.Text != "abstract contract Base {}\n" {
t.Fatalf("unexpected current PoC base: %+v", currentPoCBase)
}

for _, path := range []string{"summary.json", "summary.md", "rca.md", "Report.md", "report_bundle/visuals/asset_deltas.png", "artifacts/secret.json", "../RCA.md", "/tmp/RCA.md"} {
if _, err := reader.Read(c, path, 0); err == nil {
Expand Down
Loading