Skip to content

Handle scalar agent paths when packaging - #229

Merged
n3wth merged 3 commits into
google:mainfrom
amitvijapur:fix/packaging-validation-regression
Oct 30, 2026
Merged

n3wth merged 3 commits into
google:mainfrom
amitvijapur:fix/packaging-validation-regression

Conversation

@amitvijapur

@amitvijapur amitvijapur commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Contribution Type

  • Bug Fix / Minor Patch (Targeted fix, non-test diff <= 100 lines and < 3 core files in skills/ or agents/; no design doc required)
  • Feature / Architectural Change -- Stage 1: Design Doc PR (Refs #___ with design-ready | Adds docs/designs/<name>.md and updates docs/designs/README.md)
  • Feature / Architectural Change -- Stage 2: Implementation PR (Closes #___ with pr-ready | Implements merged docs/designs/<name>.md)

Summary of Key Changes

Claude accepts agents as one path or an array of paths. The builder applies list() to the field, splitting a single path into characters. An existing adapter supplied as a string therefore fails with ValueError: Unbundled manifest reference: ., while the equivalent one-element array succeeds.

  • Normalize a string to one reference before the existing validation. Array and missing-field behavior stay unchanged, as do containment and bundle-membership checks.
  • Reject other top-level agents types with a clear ValueError before output creation, following review feedback. Retain the list copy before appending other references.
  • Add five original scalar/list/path cases and twelve invalid-type cases across both hosts. These check folder/ZIP contents, exact manifest preservation and invalid input rejection before output creation. Remove the redundant decoded-JSON assertion while retaining the exact-byte comparisons.

Default Claude and OpenAI ZIPs are byte-identical before and after the change. Scope is offline packaging only; rollback is a normal commit revert, with no migration.

Human Accountability Affirmation

  • I am a human contributor. I have personally reviewed, understood, and can explain every line of this change in review (using AI tools to write code is welcome, but human understanding of the submitted change is required).

Prepared with Codex assistance. The review follow-up in 59efdb4 was also implemented and tested with Codex assistance and published after the contributor's approval of the presented diff.

Verification

  • For Design Doc PRs (Stage 1): Not applicable.
  • For Bug Fix / Implementation PRs (Stage 2): Unit tests added and pytest tests/unit executed; results below.
  • For Harness Support PRs: Not applicable. No live host workflow was run.

Python 3.12.13, pytest 8.3.5, PyYAML 6.0.2 on macOS:

  • Original regressions against unchanged main: four failed, one passed. With the scalar fix: five passed. A separate unchanged-main snapshot reproduced the failures.
  • Review follow-up against the original PR head 38f925d: twelve new invalid-type cases failed, with five existing controls passing. With the guard in 59efdb4: all seventeen selected cases pass.
  • Full offline suite at 59efdb4: 154 passed, one failed. The failure is the existing test_published_claude_runtime_is_current README mismatch, also reproduced on main f0ba151 and unchanged PR head 38f925d, and tracked by fix(packaging): sync the packaged readme #209. This PR does not include that unrelated fix.
  • Excluding only that baseline failure: 154 passed, one deselected.
  • Both real builder entry-point reproductions and default CLI builds pass. Default ZIP byte comparisons and git diff --check pass. The review follow-up also leaves both default ZIPs byte-identical to the original PR head.

Windows and native host/model execution were not tested. The absolute-style invalid-path case still checks allowlist rejection on Windows, not drive-absolute-path detection. The new guard validates the top-level field type, not array-element types.

Claude manifests accept one agent path or an array of paths. Normalize
the scalar form before validating bundled references so list() does not
split a path into individual characters.

Cover scalar and array output contents, manifest preservation, and
rejection of missing or escaping scalar references before output creation.
Default runtime package bytes remain unchanged.

Assisted-by: OpenAI Codex
Signed-off-by: Amit Vijapur <[email protected]>
@google-cla

google-cla Bot commented Oct 29, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@amitvijapur
amitvijapur marked this pull request as ready for review October 29, 2026 20:36

@n3wth n3wth left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed 38f925d. The fix is correct: Claude accepts agents as a string or an array, and list("./x.md") splits the string into characters, which is the Unbundled manifest reference: . failure described. Wrapping the string before the existing validation keeps the containment and bundle-membership checks on the same path for both forms, and array and missing-field behavior are unchanged.

One non-blocking item inline on the new branch: other non-string, non-list values still don't get a clear error. One test nit inline.

I ran tests/unit at this head. The new cases pass; the one failure is test_published_claude_runtime_is_current, the README.md drift that #209 addresses. I did not run Windows or a live host. cla/google and the scope/template check pass.

Nothing blocking.

Comment thread scripts/pack_plugin.py Resolved
Comment thread tests/unit/test_packaging.py Resolved
Reject non-string, non-list agents values before packaging output is
created. Preserve scalar normalization, list copying and reference checks.

Add invalid-type regressions for both hosts and remove a redundant
parsed-manifest assertion covered by exact-byte comparisons.

Assisted-by: OpenAI Codex
Signed-off-by: Amit Vijapur <[email protected]>

@n3wth n3wth left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed at 59efdb4. The only change since 38f925d is the follow-up to my last round: agents must now be a string or a list, anything else raises ValueError: Invalid manifest agents: ... before the output directory is created, and the redundant json.loads comparison is gone from the scalar test. Keeping list(agents) is fine, since it copies before the icon and logo references are appended. Containment and bundle-membership checks are unchanged for both forms.

The new tests cover None, 5, True, {}, a non-empty dict and 1.5 on both hosts, and assert the exact message and that the output is not created. The scalar tests also check missing.md, ../escape.md and an absolute path against the allowlist.

I ran tests/unit locally at this head. The one failure is test_published_claude_runtime_is_current, the README.md drift that #209 fixes. I did not run Windows or a live host. cla/google and the scope/template check pass.

No remaining finding.

Comment thread scripts/pack_plugin.py Resolved
@n3wth
n3wth merged commit bcf0394 into google:main Oct 30, 2026
10 checks passed
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.

2 participants