Skip to content

fix: correct malformed CreateArtifact Twirp request, make upload_artifact failures non-fatal, and add live API integration tests#39008

Merged
pelikhan merged 9 commits into
mainfrom
copilot/aw-failures-fix-upload-artifact-request
Jun 13, 2026
Merged

fix: correct malformed CreateArtifact Twirp request, make upload_artifact failures non-fatal, and add live API integration tests#39008
pelikhan merged 9 commits into
mainfrom
copilot/aw-failures-fix-upload-artifact-request

Conversation

Copilot AI commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

upload_artifact was failing every safe_outputs job with HTTP 400 malformed: the json request could not be decoded due to two bugs in the Twirp request body, and a failing upload was propagating as a fatal error that took down the entire job even when the agent and all other safe outputs succeeded.

artifact_client.cjs — malformed Twirp request fields

Two encoding errors in CreateArtifact / FinalizeArtifact:

  1. StringValue fields encoded as wrapper objects instead of plain strings. Per the proto3 JSON spec, google.protobuf.StringValue serializes as a bare JSON string. The server received {"value":"application/zip"} and could not decode it.
  2. Snake_case field names instead of camelCase. Proto3 JSON uses workflowRunBackendId, not workflow_run_backend_id.
// Before (malformed — causes 400)
{
  workflow_run_backend_id: "...",
  mime_type: { value: "application/zip" },   // StringValue wrapper ← wrong
  expires_at: "...",
}

// After (correct proto3 JSON)
{
  workflowRunBackendId: "...",
  mimeType: "application/zip",               // plain string
  expiresAt: "...",
}

Same fix applied to FinalizeArtifact's hash field ({ value: "sha256:..." }"sha256:..."). Response parsing reads both camelCase and snake_case variants (signedUploadUrl/signed_upload_url, artifactId/artifact_id) for robustness.

safe_output_handler_manager.cjs — upload_artifact failures now non-fatal

Added upload_artifact to REPORT_ONLY_FAILURE_TYPES alongside assign_to_agent. A failed artifact upload now emits a warning and is counted separately rather than calling core.setFailed, so it no longer brings down an otherwise-successful safe_outputs job.

Tests

  • artifact_client.test.cjs: asserts CreateArtifact/FinalizeArtifact requests use camelCase names and plain-string mimeType/hash.
  • safe_output_handler_manager.test.cjs: asserts upload_artifact failures are partitioned as report-only, not fatal.

Live API integration tests (cjs.yml)

Added a new artifact-integration CI job to cjs.yml that cross-validates our DefaultArtifactClient against the official @actions/artifact SDK end-to-end:

  • Test 1 — custom → SDK: uploads a file with our DefaultArtifactClient (via Twirp CreateArtifact/FinalizeArtifact), then lists and downloads the artifact using the official @actions/artifact SDK, verifying our request encoding is server-compatible.
  • Test 2 — SDK → custom: uploads a file with the official @actions/artifact SDK, then lists and downloads it with our DefaultArtifactClient, verifying our list/download logic is compatible with SDK-produced artifacts.

Both tests skip gracefully with an explanatory message when ACTIONS_RUNTIME_TOKEN/ACTIONS_RESULTS_URL are absent (i.e. outside a GitHub Actions job). The job runs with permissions: actions: write and injects GITHUB_TOKEN for the REST-based download step. @actions/artifact is added as a devDependency.

Copilot AI and others added 2 commits June 13, 2026 04:04
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…t non-fatal

- Fix artifact_client.cjs to use camelCase field names (workflowRunBackendId,
  workflowJobRunBackendId, mimeType, expiresAt) matching the proto3 JSON spec
- Fix mimeType to be a plain string instead of a wrapped { value: ... } object,
  which caused HTTP 400 "the json request could not be decoded" from the Twirp API
- Fix hash field in FinalizeArtifact to be a plain string instead of { value: ... }
- Make upload_artifact failures non-fatal in safe_output_handler_manager.cjs:
  a failed artifact upload now emits a warning rather than failing the entire
  safe_outputs job (matching the existing behaviour for assign_to_agent)
- Update tests to assert correct camelCase field names and plain-string mimeType/hash
- Add upload_artifact to the report-only failure tests

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix malformed CreateArtifact request in upload_artifact handler fix: correct malformed CreateArtifact Twirp request and make upload_artifact failures non-fatal Jun 13, 2026
Copilot AI requested a review from pelikhan June 13, 2026 04:14
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot compare changes with sources in actions/toolkit upload-artifact

Copilot AI commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot compare changes with sources in actions/toolkit upload-artifact

Compared against packages/artifact/src/internal/upload/upload-artifact.ts and the generated proto types.

The toolkit uses ArtifactServiceClientJSON (protobuf-ts) which serialises google.protobuf.StringValue as a bare JSON string and google.protobuf.Timestamp as an RFC 3339 string, per the proto3 JSON spec. Our artifact_client.cjs directly constructs the raw JSON body, so we need to reproduce that output manually.

Field Toolkit (after protobuf-ts serialisation) Our implementation
mimeType (StringValue) "application/zip" contentType (plain string) ✅
hash (StringValue) "sha256:…" `sha256:${sha256}` (plain string) ✅
expiresAt (Timestamp) RFC 3339 string .toISOString()
size (int64 as string) uploadSize.toString() String(uploadSize)
version 7 7
Field names camelCase (workflowRunBackendId, …) camelCase ✅

Response parsing uses snake_case (signed_upload_url, artifact_id) because the toolkit's own maskSecretUrls helper checks for signed_upload_url in the raw response body, confirming the server returns snake_case keys.

The request encoding in this PR matches what the toolkit sends after protobuf-ts serialises the proto types.

@pelikhan pelikhan marked this pull request as ready for review June 13, 2026 04:33
Copilot AI review requested due to automatic review settings June 13, 2026 04:34

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

This PR fixes GitHub Actions artifact uploads in safe_outputs by correcting the Twirp/proto3 JSON request encoding for CreateArtifact / FinalizeArtifact, and by making upload_artifact failures non-fatal so they don’t fail an otherwise-successful safe_outputs job.

Changes:

  • Update CreateArtifact/FinalizeArtifact request bodies to use proto3 JSON conventions (camelCase field names and plain-string StringValue fields).
  • Treat upload_artifact failures as report-only (warn + summarize) instead of failing the job.
  • Add/extend tests covering the request encoding and report-only partitioning behavior.
Show a summary per file
File Description
actions/setup/js/artifact_client.cjs Adjusts artifact Twirp request payload fields for proto3 JSON correctness.
actions/setup/js/artifact_client.test.cjs Adds a test asserting the corrected request body encoding.
actions/setup/js/safe_output_handler_manager.cjs Marks upload_artifact failures as report-only and updates reporting output.
actions/setup/js/safe_output_handler_manager.test.cjs Adds tests ensuring upload_artifact failures are treated as report-only (not fatal).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (1)

actions/setup/js/artifact_client.cjs:360

  • The Twirp/proto3 JSON mapping uses lowerCamelCase field names in responses as well. After switching request bodies to camelCase, this code still expects signed_upload_url, so a canonical signedUploadUrl response would be treated as invalid and break uploads.
      createRequest.expiresAt = expiresAt;
    }

    /** @type {any} */
    const createResponse = await twirpRequest("CreateArtifact", createRequest);
  • Files reviewed: 4/4 changed files
  • Comments generated: 4

Comment on lines +369 to +373
workflowRunBackendId,
workflowJobRunBackendId,
name: artifactName,
size: String(uploadSize),
hash: { value: `sha256:${sha256}` },
hash: `sha256:${sha256}`,
Comment thread actions/setup/js/artifact_client.test.cjs Outdated
Comment on lines 555 to 557
function isReportOnlyFailureResult(result) {
return isFailedProcessingResult(result) && result?.type === "assign_to_agent";
return isFailedProcessingResult(result) && (result?.type === "assign_to_agent" || result?.type === "upload_artifact");
}
Comment thread actions/setup/js/safe_output_handler_manager.cjs Outdated
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

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

No ADR enforcement needed: PR #39008 does not have the 'implementation' label (has_implementation_label=false) and has 0 new lines of code in business logic directories (default_business_additions=0, well under the 100-line threshold). Neither Condition A nor Condition B is met.

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions github-actions Bot mentioned this pull request Jun 13, 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 /diagnose and /tdd — no blocking issues, but two maintainability concerns worth addressing before this pattern expands further.

📋 Key Themes & Highlights

Key Themes

  • DRY violation in safe_output_handler_manager.cjs: isReportOnlyFailureResult maintains its own inline OR chain while REPORT_ONLY_FAILURE_TYPES Set exists alongside it. partitionFailureResults uses the Set directly and skips the predicate entirely — two implementations of the same concept that will diverge on the next addition.
  • Missing test path: the regression test covers application/octet-stream only; application/zip (the path from the original bug report) has no coverage.

Positive Highlights

  • ✅ Root cause properly identified and fixed at both callsites (CreateArtifact and FinalizeArtifact)
  • REPORT_ONLY_FAILURE_TYPES Set is a good extensibility improvement for partitionFailureResults
  • ✅ Warning message now emits actual failure types instead of hardcoded copy — great observability improvement
  • ✅ Tests for isReportOnlyFailureResult cover skipped/cancelled edge cases cleanly
  • ✅ Mixed fatal+report-only partition test is well-structured

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 254.9 AIC · ⌖ 13.3 AIC · ⊞ 27.8K

*/
function isReportOnlyFailureResult(result) {
return isFailedProcessingResult(result) && result?.type === "assign_to_agent";
return isFailedProcessingResult(result) && (result?.type === "assign_to_agent" || result?.type === "upload_artifact");

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.

[/diagnose] isReportOnlyFailureResult duplicates the type list from REPORT_ONLY_FAILURE_TYPES, creating a divergence risk — a future maintainer adding a type to the Set will not automatically update this inline OR chain.

💡 Suggested fix

Move REPORT_ONLY_FAILURE_TYPES above this function, then have the function delegate to the Set:

const REPORT_ONLY_FAILURE_TYPES = new Set(["assign_to_agent", "upload_artifact"]);

function isReportOnlyFailureResult(result) {
  return isFailedProcessingResult(result) && REPORT_ONLY_FAILURE_TYPES.has(result?.type);
}

This makes the Set the single source of truth for both this predicate and partitionFailureResults.

const failedResults = results.filter(isFailedProcessingResult);
const reportOnlyFailures = failedResults.filter(r => r?.type === "assign_to_agent");
const fatalFailures = failedResults.filter(r => r?.type !== "assign_to_agent");
const reportOnlyFailures = failedResults.filter(r => REPORT_ONLY_FAILURE_TYPES.has(r?.type));

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.

[/diagnose] partitionFailureResults uses REPORT_ONLY_FAILURE_TYPES.has(r?.type) directly rather than calling isReportOnlyFailureResult, so a bug in the predicate (e.g. a missing isFailedProcessingResult guard) would affect tests but not the real partitioning path.

💡 Suggested fix

Once isReportOnlyFailureResult delegates to the Set (see companion comment on line 556), this function can use the predicate directly:

const reportOnlyFailures = failedResults.filter(r => isReportOnlyFailureResult(r));
const fatalFailures = failedResults.filter(r => !isReportOnlyFailureResult(r));

This collapses two implementations of the same concept into one.

vi.stubEnv("ACTIONS_RESULTS_URL", "https://results.example.com");

const client = new DefaultArtifactClient();
await client.uploadArtifact("my-artifact", [filePath], tmpDir, { skipArchive: true, retentionDays: 30 });

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] This test only exercises the skipArchive: true path, which uses application/octet-stream. The original bug was reported with application/zip (the default zip-archive path), so that path has no regression coverage.

💡 Suggested addition

Add a second test without skipArchive to lock in the zip-path encoding:

it("sends mimeType as a plain string when artifact is a zip archive", async () => {
  // same mock setup...
  let capturedMimeType = null;
  // capture mimeType from CreateArtifact body
  await client.uploadArtifact("my-artifact", [filePath], tmpDir, { retentionDays: 1 });
  expect(typeof capturedMimeType).toBe("string");
  expect(capturedMimeType).toBe("application/zip");
});

This would have caught the original { value: "application/zip" } regression.

await expect(client.uploadArtifact("art", ["/a", "/b"], tmpDir, { skipArchive: true })).rejects.toThrow("single file");
});

it("sends camelCase field names and mimeType as a plain string in CreateArtifact request", async () => {

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 test name says "in CreateArtifact request" but the test also asserts the FinalizeArtifact body (lines 261–268). Consider renaming it to make the full scope discoverable at a glance:

"sends correctly encoded camelCase fields in CreateArtifact and FinalizeArtifact requests"

@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.

REQUEST_CHANGES: two issues introduced in this PR need fixing before merge.

Blocking issues

isReportOnlyFailureResult diverges from REPORT_ONLY_FAILURE_TYPES

The PR introduces REPORT_ONLY_FAILURE_TYPES as the canonical Set for partitionFailureResults, but isReportOnlyFailureResult keeps a parallel hardcoded OR-chain. Both are exported. A future type addition to the Set will silently leave the predicate stale. Fix: move the Set above the function and have it use REPORT_ONLY_FAILURE_TYPES.has(result?.type).

Non-fatal warning is undiagnosable

The updated core.warning logs only type names, not error messages. The fatal-failure path at line 1509 includes r.error; this warning should too. Also, unlike every other type-list in this file, .map() here has no new Set() dedup, so repeated failures produce a noisy repeated list.

Non-blocking (no comment posted)
  • core.info("Reported assignment failures: ...") at line 1476 was not updated — the count now includes artifact upload failures but the label still says "assignment".

🔎 Code quality review by PR Code Quality Reviewer · 432.8 AIC · ⌖ 13.2 AIC · ⊞ 16.7K

*/
function isReportOnlyFailureResult(result) {
return isFailedProcessingResult(result) && result?.type === "assign_to_agent";
return isFailedProcessingResult(result) && (result?.type === "assign_to_agent" || result?.type === "upload_artifact");

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.

isReportOnlyFailureResult ignores REPORT_ONLY_FAILURE_TYPES: this exported function hardcodes the type list inline, diverging from the Set introduced three lines below—adding a third type to the Set will silently break this function and any callers.

💡 Suggested fix

Move REPORT_ONLY_FAILURE_TYPES above this function and delegate to it:

const REPORT_ONLY_FAILURE_TYPES = new Set(["assign_to_agent", "upload_artifact"]);

function isReportOnlyFailureResult(result) {
  return isFailedProcessingResult(result) && REPORT_ONLY_FAILURE_TYPES.has(result?.type);
}

The Set was introduced as the canonical list for partitionFailureResults, but isReportOnlyFailureResult was left with an independent hardcoded OR-chain. Any future addition to the Set requires a second independent edit here with no compile-time guarantee they stay in sync.

Comment on lines +1514 to +1515
const reportOnlyTypes = reportOnlyFailures.map(r => r.type || "unknown");
core.warning(`${reportOnlyFailureCount} non-fatal safe output(s) failed but were reported without failing safe_outputs: ${reportOnlyTypes.join(", ")}`);

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.

Non-fatal warning omits error details and may be repetitive: unlike the fatal-failure path that logs r.error, this warning only logs type names, making upload_artifact failures undiagnosable from the warning alone.

💡 Suggested fix

Include error strings and deduplicate types like the rest of the file does:

const reportOnlyItems = reportOnlyFailures.map(r => `${r.type || "unknown"}: ${r.error || "unknown error"}`);
core.warning(`${reportOnlyFailureCount} non-fatal safe output(s) failed but were reported without failing safe_outputs:\n${reportOnlyItems.join("\n")}`);

Additionally, every other type-list construction in this file uses [...new Set(...)] to deduplicate. If multiple upload_artifact calls fail, the raw .map() here will produce a repeated list of type names in the warning, inconsistent with the rest of the summary logging.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 82/100 — Excellent

Analyzed 4 test(s): 4 design, 0 implementation, 0 guideline violation(s).

📊 Metrics & Test Classification (4 tests analyzed)
Metric Value
New/modified tests analyzed 4
✅ Design tests (behavioral contracts) 4 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 3 (75%)
Duplicate test clusters 0
Test inflation detected Yes — artifact_client.test.cjs 56/7 = 8:1, safe_output_handler_manager.test.cjs 37/10 = 3.7:1 (see note below)
🚨 Coding-guideline violations 0

Note on inflation: Both ratios exceed the 2:1 threshold mechanically, but the high ratios are expected here. The artifact_client fix changes 7 field-name pairs; testing it requires mocking the fetch boundary to capture the outgoing HTTP body — that boilerplate accounts for most of the added lines. The tests are genuinely high-value despite the ratio.

Test Classification Details

Test File Classification Edge Cases Assertions vi.* Mocks
sends camelCase field names and mimeType as a plain string in CreateArtifact request artifact_client.test.cjs ✅ Design No (happy-path + negative assertions) 16 vi.fn, vi.stubGlobal(fetch), vi.stubEnv ×2 (all external I/O)
treats failed upload_artifact results as report-only safe_output_handler_manager.test.cjs ✅ Design Yes (failure scenario) 1 None
does not treat skipped or cancelled upload_artifact results as report-only safe_output_handler_manager.test.cjs ✅ Design Yes (skipped/cancelled boundary) 2 None
partitions upload_artifact failures as report-only, not fatal safe_output_handler_manager.test.cjs ✅ Design Yes (mixed result partitioning) 2 None

Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 0 tests — no Go test files changed
  • 🟨 JavaScript (*.test.cjs, *.test.js): 4 tests (vitest)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). All 4 new tests verify observable behavioral contracts directly tied to the two bugs fixed in this PR (malformed Twirp field names, and non-fatal upload_artifact failure classification).

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

References: §27456668992

🧪 Test quality analysis by Test Quality Sentinel · 263.3 AIC · ⌖ 19.3 AIC · ⊞ 27.2K ·

@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: 82/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 4 new tests verify behavioral contracts tied directly to the two bugs fixed in this PR.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

…er_manager

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

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

Copilot AI commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Done. Addressed all four review threads from the automated review:

  1. artifact_client.cjs response parsing — now reads both signedUploadUrl/signed_upload_url and artifactId/artifact_id (camelCase preferred, snake_case fallback). Uses ?? (nullish coalescing) rather than || for the ID to avoid falsy-zero confusion.
  2. Test stubs — updated all CreateArtifact/FinalizeArtifact mock responses to use camelCase keys (signedUploadUrl, artifactId) so the tests exercise the primary code path.
  3. isReportOnlyFailureResult — moved REPORT_ONLY_FAILURE_TYPES before the function and rewrote the predicate as result?.type && REPORT_ONLY_FAILURE_TYPES.has(result.type), eliminating the duplicated type list.
  4. Dedup warning — report-only type names in the warning are now deduplicated with new Set(...).

All 100 JS tests pass locally. CI needs a human re-trigger after these pushes.

@github-actions

Copy link
Copy Markdown
Contributor

Please re-trigger CI and summarize any remaining blockers.

Generated by 👨‍🍳 PR Sous Chef · 43.8 AIC · ⌖ 1.07 AIC · ⊞ 17.3K ·

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot

  • add integration test job that uploads and downloads artifacts using live APIs. Cjs.yml
  • run pr-finisher skill

@github-actions

Copy link
Copy Markdown
Contributor

@copilot please summarize the remaining blocker and next step for this PR.

Generated by 👨‍🍳 PR Sous Chef · 71.5 AIC · ⌖ 0.957 AIC · ⊞ 17.3K ·

Copilot AI and others added 2 commits June 13, 2026 10:31
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…n test

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

Copilot AI commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot

  • add integration test job that uploads and downloads artifacts using live APIs. Cjs.yml...

Done. Added in commit feat: add artifact API integration test job to cjs.yml:

  • artifact_client_live_api.test.cjs — end-to-end test that uploads a file via the Twirp API, lists artifacts to verify it appears, downloads it, and asserts the content matches. Skips gracefully with an explanatory message when ACTIONS_RUNTIME_TOKEN/ACTIONS_RESULTS_URL are absent (outside a GHA job).
  • vitest.artifact-integration.config.mjs — dedicated Vitest config for the artifact integration suite (120 s test timeout for real network I/O).
  • package.json — new test:js-integration-artifact script.
  • cjs.yml artifact-integration jobubuntu-latest, permissions: actions: write, injects GITHUB_TOKEN, runs npm run test:js-integration-artifact.

Copilot AI changed the title fix: correct malformed CreateArtifact Twirp request and make upload_artifact failures non-fatal fix: correct malformed CreateArtifact Twirp request, make upload_artifact failures non-fatal, and add live API integration tests Jun 13, 2026
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot

…idation in integration tests

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

Copilot AI commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot

Fixed in the latest commit:

  1. TypeScript CI failure (safe_output_handler_manager.cjs:570-571) — Set<string>.has() was receiving string | undefined. Changed r?.typer?.type ?? "" in both filter lambdas inside partitionFailureResults.

  2. @actions/artifact SDK cross-validation — installed @actions/artifact@6.2.1 as a devDependency and rewrote artifact_client_live_api.test.cjs with two cross-validation tests:

    • Test 1: upload with our DefaultArtifactClient → list + download with the official SDK (verifies our Twirp request encoding is server-compatible)
    • Test 2: upload with the official SDK → list + download with our DefaultArtifactClient (verifies our list/download is compatible with SDK-produced artifacts)

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run npm update to get latest packages (with cooldown)

@pelikhan pelikhan merged commit eb1c874 into main Jun 13, 2026
21 checks passed
@pelikhan pelikhan deleted the copilot/aw-failures-fix-upload-artifact-request branch June 13, 2026 11:19
Copilot stopped work on behalf of pelikhan due to an error June 13, 2026 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants