Skip to content

Prevent raw observability log loss during artifact extraction - #51907

Merged
pelikhan merged 9 commits into
mainfrom
copilot/deep-report-fix-log-retention-issue
Aug 11, 2026
Merged

Prevent raw observability log loss during artifact extraction#51907
pelikhan merged 9 commits into
mainfrom
copilot/deep-report-fix-log-retention-issue

Conversation

Copilot AI commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Firewall and MCP raw logs were present in the unified agent artifact but disappeared during filtered downloads. Overlapping files from usage, agent, and detection artifacts caused extraction to abort before nested access.log and rpc-messages.jsonl files were reached.

  • Isolate extraction

    • Download each named artifact into its own staging directory.
    • Preserve existing flattening behavior after collision-free extraction.
  • Harden artifact names

    • Reject empty, traversal, and cross-platform separator-containing names before constructing staging paths.
  • Add regression coverage

    • Model overlapping artifact files.
    • Verify nested firewall and MCP raw logs survive extraction.
    • Cover unsafe artifact-name inputs.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.3 AIC · ⌖ 5.17 AIC · ⊞ 8.5K ·
Comment /souschef to run again

Copilot AI and others added 4 commits August 11, 2026 03:10
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix firewall/MCP raw-log retention failure Prevent raw observability log loss during artifact extraction Aug 11, 2026
Copilot AI requested a review from pelikhan August 11, 2026 03:19
@pelikhan
pelikhan marked this pull request as ready for review August 11, 2026 03:21
Copilot AI balanced review requested due to automatic review settings August 11, 2026 03:21
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Lean already. Ship.

Generated by Ponytail Reviewer for #51907

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • api.individual.githubcopilot.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "api.individual.githubcopilot.com"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #51907 does not have the 'implementation' label and has only 71 new lines of code in business logic directories (threshold: 100).

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

🧪 Test quality analysis by Test Quality Sentinel

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Isolates artifact extraction to prevent filename collisions from dropping observability logs.

Changes:

  • Extracts each artifact into a dedicated directory.
  • Validates artifact names against unsafe paths.
  • Adds collision and validation regression coverage.
Show a summary per file
File Description
pkg/cli/logs_download_artifacts.go Adds isolated extraction and name validation.
pkg/cli/logs_artifact_set.go Reuses centralized validation for markers.
pkg/cli/logs_download_test.go Tests isolated downloads and updates fixtures.
pkg/cli/logs_artifact_set_test.go Expands unsafe-name tests.

Review details

Tip

Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Balanced

if err := validateArtifactName(name); err != nil {
return err
}
artifactDir := filepath.Join(opts.outputDir, name)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2e94fd8: named artifacts now download into temporary sibling staging directories and are promoted to the artifact directory only after gh run download succeeds, so failed extractions cannot satisfy cache checks.

Comment thread pkg/cli/logs_download_artifacts.go Outdated
Comment on lines +136 to +137
artifactDir := filepath.Join(opts.outputDir, name)
args := []string{"run", "download", strconv.FormatInt(opts.runID, 10), "--name", name, "--dir", artifactDir}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2e94fd8: usage-only downloads now copy usage/aw_info.json to the run root before attempting activation fallback, preserving existing metadata layout and avoiding unnecessary fallback downloads.

Comment thread pkg/cli/logs_download_test.go Outdated
Comment on lines +374 to +378
err := downloadArtifactsByName(
context.Background(),
downloadArtifactsOptions{runID: 12345, outputDir: outputDir},
[]string{"usage", "agent"},
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2e94fd8: the regression now exercises downloadRunArtifacts end-to-end and asserts the final flattened mcp-logs/rpc-messages.jsonl and sandbox/firewall/logs/access.log paths survive overlapping artifacts.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Prevent raw observability log loss during artifact extraction

This PR correctly addresses two issues:

  1. Artifact isolation — Each artifact now extracts into outputDir/<name>/ instead of the shared outputDir/, preventing cross-artifact file collisions.

  2. Path traversal hardeningvalidateArtifactName consolidates and strengthens the existing check by also rejecting ., .., and names containing forward/backslashes, before filepath.Base normalization catches them.

  3. Test fixture alignment — Existing fake-gh shell scripts updated from $dir/$name/... to $dir/... to match the new isolation layout.

No blocking issues found. LGTM.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 24.5 AIC · ⌖ 6.16 AIC · ⊞ 5.4K

@github-actions github-actions Bot mentioned this pull request Aug 11, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — two low-severity observations; no blocking issues.

📋 Key Themes & Highlights

Key Themes

  • Isolation fix is correct: downloading each artifact into opts.outputDir/<name> eliminates the collision root cause cleanly. flattenUnifiedArtifactfindArtifactDir finds outputDir/agent as before, so the existing flatten pipeline still works.
  • validateArtifactName placement: called in downloadArtifactsByName but not in retryCriticalArtifacts (inline comment filed). Low risk since names come from constants, but asymmetric.
  • Regression test is solid: the fake-gh script in TestDownloadArtifactsByName_IsolatesArtifactExtraction directly models the collision scenario and asserts nested files survive — this is exactly the right test for the bug.
  • Existing test updates: the TestDownloadRunArtifacts_CachedUsageFallbackToActivation and TestDownloadRunArtifactsFallbackWhenListFails script adjustments correctly mirror the new --dir semantics (no subdirectory creation inside the script).

Positive Highlights

  • validateArtifactName extracted as a shared helper — DRY and testable
  • ✅ Traversal-safety hardened: strings.ContainsAny(name, "/\\") + filepath.Base double-check
  • ✅ New test covers nested mcp-logs/ and sandbox/firewall/logs/ paths — the exact files that were being lost

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 41.8 AIC · ⌖ 6.67 AIC · ⊞ 7.1K
Comment /matt to run again

Comment thread pkg/cli/logs_download_artifacts.go Outdated
}

retryArgs := []string{"run", "download", strconv.FormatInt(opts.runID, 10), "--name", name, "--dir", opts.outputDir}
retryArgs := []string{"run", "download", strconv.FormatInt(opts.runID, 10), "--name", name, "--dir", filepath.Join(opts.outputDir, name)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/diagnosing-bugs] retryCriticalArtifacts skips validateArtifactName even though it constructs a filepath.Join path from name. Since criticalArtifactNames are compile-time constants this is safe today, but the asymmetry is a maintenance trap.

💡 Suggestion

Add validation at the top of the loop, mirroring downloadArtifactsByName:

if err := validateArtifactName(name); err != nil {
    logsDownloadLog.Printf("Skipping invalid critical artifact name: %v", err)
    continue
}

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2e94fd8: retryCriticalArtifacts now validates critical artifact names before constructing staging paths.

assert.FileExists(t, filepath.Join(outputDir, "agent", "sandbox", "firewall", "logs", "access.log"))
}

func TestDownloadRunArtifacts_CachedUsageFallbackToActivation(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The fake gh script exits 1 on a collision (if [ -e "$dir/shared.json" ]), but the test never asserts that no error occurred after downloading both usage and agent — it just calls require.NoError. If the isolation fix regresses, the script collision would surface as a test failure but the error message would be opaque (exit status 1 with no artifact context).

💡 Suggestion

Capture and log the fake-script stderr, or add a comment explaining that require.NoError on line 376 IS the regression gate, so future readers understand the test structure at a glance.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2e94fd8: the test now documents the require.NoError regression gate and covers the production download-and-flatten path.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

⚠️ Test Quality Score: 52/100 — Acceptable

Analyzed 2 test files with ~40 test functions: 2 design tests, ~30+ implementation tests, 0 violations.

📊 Metrics
Metric Value
Test Functions Analyzed ~40 (Go: 40, JS: 0)
✅ Design/Contract Tests 2 (5%) — Critical behavioral coverage
⚠️ Implementation Tests ~30+ (75%) — Table-driven, utility, helper functions
🔍 Edge/Error Cases Comprehensive — Collision handling, path traversal, invalid names
Test Inflation Ratio 3.8:1 (+49 test lines / +13 prod lines) — Slightly elevated
🚨 Violations 0 — No mock libraries, proper build tags, safe input validation

📋 Test Classifications

🟢 HIGH-VALUE Design Tests (Behavioral Contracts)

Test Name File Classification Coverage
TestDownloadArtifactsByName_IsolatesArtifactExtraction logs_download_test.go:346 behavioral_contract, high_value, design_test Artifact staging isolation, collision prevention, nested logs preservation
TestMarkArtifactDownloadedRejectsInvalidNames logs_artifact_set_test.go:455 behavioral_contract, high_value, design_test Path traversal prevention, unsafe name rejection

🔵 IMPLEMENTATION Tests (Table-Driven, Comprehensive)

Category Count Examples
Artifact Set Validation ~8 TestValidateArtifactSets, TestResolveArtifactFilter, TestArtifactMatchesFilter
Filter Logic ~6 TestFindMissingFilterEntries (incremental scenario, full names, marker satisfaction)
Utility Functions ~8 TestDirExists, TestIsDirEmpty, TestCriticalArtifactNames, error pattern tests
Integration Scenarios ~3 TestDownloadRunArtifacts_CachedUsageFallbackToActivation, fallback logic

⚪ SUPPORT Tests (Infrastructure, Constants)

  • Constant verification (TestCriticalArtifactNames)
  • Error type definitions (TestErrNoArtifacts)
  • String pattern matching (TestIsNonZipArtifactError, TestIsCaseCollisionArtifactError)
✅ Strengths
  1. Critical Behavioral Test: TestDownloadArtifactsByName_IsolatesArtifactExtraction directly validates the core fix (isolation of artifact extraction to prevent collision-induced data loss).

    • Simulates realistic overlapping files (shared.json from both usage and agent artifacts)
    • Verifies nested logs survive extraction: mcp-logs/rpc-messages.jsonl, sandbox/firewall/logs/access.log
    • Uses fake shell script (realistic scenario, not over-mocked)
  2. Security-Focused: TestMarkArtifactDownloadedRejectsInvalidNames validates input hardening against path traversal (../activation, ..\ activation, ., ..).

  3. Comprehensive Edge Cases:

    • Incremental download scenarios (TestFindMissingFilterEntriesIncrementalScenario)
    • Marker satisfaction logic (TestFindMissingFilterEntriesAllMarkerSatisfiesFiltered)
    • Path traversal prevention in zip extraction (TestUnzipFileZipSlipPrevention)
  4. No Violations: No gomock/testify/mock library usage; proper (go/redacted):build !integration tags; clear error messages in assertions.

  5. Table-Driven Rigor: ~12 table-driven tests with comprehensive scenario coverage (happy path + error/edge cases).

⚠️ Observations
  1. Test Inflation: +49 test lines vs. +13 production lines (3.8:1 ratio, exceeds 2:1 threshold by ~1.8x).

    • Justification: Integration-style test with realistic shell scenarios; warranted for this bug-fix PR.
    • Recommendation: Acceptable; inflation is tied to the critical isolation test.
  2. Implementation-Heavy: ~75% of tests are implementation-level (validation logic, helpers, utilities) rather than high-level behavioral contracts.

    • This is typical and expected for utility/infrastructure refactoring PRs.
    • The 2 design tests provide strong coverage of the user-visible behavioral change.
  3. No Test Infrastructure Changes: No new TestMain, no goleak.VerifyTestMain additions (infrastructure-only PRs would be evaluated differently).

📝 Verdict

✅ APPROVED. Test quality is acceptable.

  • Design Test Ratio: 5% (2 critical tests validating artifact isolation and input safety)
  • Edge Case Coverage: Comprehensive (collisions, traversal, invalid names, incremental scenarios)
  • Violations: None

This PR prioritizes regression testing for a specific bug fix (artifact extraction isolation) with solid supporting infrastructure tests. The core behavioral contract (TestDownloadArtifactsByName_IsolatesArtifactExtraction) is high-value and directly tests the fix for issue #51813. Implementation-level testing is thorough (table-driven) and provides confidence in the refactored artifact filtering logic.

🧪 Test quality analysis by Test Quality Sentinel · haiku45 · 35.1 AIC · ⌖ 4.06 AIC · ⊞ 7.6K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 52/100 (Acceptable). Design tests: 5% (2 critical). Implementation tests: 75% (threshold: 30%). Edge case coverage: Comprehensive (collisions, traversal, invalid names). Violations: 0. The core behavioral test TestDownloadArtifactsByName_IsolatesArtifactExtraction directly validates the fix for issue #51813 with realistic scenarios. Approved.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

Copilot AI and others added 3 commits August 11, 2026 03:59
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot quick triage: this PR looks close, but it still has a recent Matt skills review with two low-severity follow-ups and a fresh maintainer request to run the pr-finisher skill. Please review the latest feedback, decide whether the validateArtifactName asymmetry in retryCriticalArtifacts needs a defensive follow-up or an explicit rationale, confirm the branch is fully maintainer-ready, then run the pr-finisher skill and reply with a concise maintainer-facing summary.

Branch refresh was requested. Run: https://github.com/github/gh-aw/actions/runs/31456898570

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.3 AIC · ⌖ 5.17 AIC · ⊞ 8.5K ·
Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Ran the PR finisher pass. Addressed the in-scope review feedback, pushed fixes through 2e94fd8, and completed local validation. CI on the latest agent-pushed HEAD still needs a maintainer re-trigger before merge.

@pelikhan
pelikhan merged commit d4d0a11 into main Aug 11, 2026
2 of 3 checks passed
@pelikhan
pelikhan deleted the copilot/deep-report-fix-log-retention-issue branch August 11, 2026 04:18
Copilot stopped work on behalf of gh-aw-bot due to an error August 11, 2026 04:18
Copilot AI requested a review from gh-aw-bot August 11, 2026 04:18
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.86.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[deep-report] Firewall/MCP raw-log retention has failed 6 fix attempts since Feb — check upload-side glob/path-depth mismatch

4 participants