Skip to content

publish api: POST security-advisories always fails with opaque gh-failed #129

Open

Description

@woksin

Problem

The publish tool with kind: api, method: POST and endpoint: repos/<owner>/<repo>/security-advisories returns publish: gh-failed with no detail, every time. A draft repository security advisory cannot be created through the guarded path, and the publish guard blocks direct gh api writes, so there is no sanctioned way to file a private advisory.

Attempts (all gh-failed)

  1. summary, description (file field), cvss_vector_string, vulnerabilities[0][package][ecosystem|name], vulnerabilities[0][vulnerable_version_range]
  2. summary, description (file), severity
  3. as 2, plus vulnerabilities[][package][ecosystem|name] and vulnerabilities[][vulnerable_version_range]
  4. as 2, plus vulnerabilities = null
  5. a different repository, with cwe_ids[] repeated

GET .../security-advisories works with the same credentials.

Expected

  • The tool reports gh's stderr (status code and the API's error message), redacted as needed.
  • Arrays of objects (vulnerabilities[][package][name]) can be sent. The GitHub API requires the vulnerabilities array, and gh api -f cannot express arrays of objects, so api requests probably need a JSON body (--input) mode.

Also seen

issue-create with a bodyFile under the repository's ignored work folder returned payload-unreadable, while issue-comment with a file in the same folder worked minutes earlier.

Activity

  1. woksin commented on Nov 7, 2026

    @woksin
    OwnerAuthor

    Two more independent reproductions from separate sessions, same result: publish with kind: api, method: POST, endpoint: repos/<org>/<repo>/security-advisories returns only publish: gh-failed.

    Payload variants tried (all failed identically):

    1. summary, description (from a file field), severity: medium
    2. the same plus vulnerabilities[][package][ecosystem] / [name]
    3. the same with vulnerabilities: null
    4. (second session) vulnerabilities[0].package.ecosystem: other

    The calling account has admin permission on the target repository, and a read of the same endpoint (list advisories) succeeds, so access is not the obvious cause. The failure body from GitHub is not surfaced, so the caller cannot tell a field-shape problem from a permission or scanner problem, and the guard rules out calling gh api directly to find out.

    Expected: the GitHub error status and message (value-free is fine) in the tool result, or documented support for nested array fields in fields.

  2. woksin commented on Nov 8, 2026

    @woksin
    OwnerAuthor

    Additional evidence (PATCH variant, root cause identified):

    • publish kind: api, method: PATCH on a repository security-advisory endpoint with fields vulnerabilities[][package][ecosystem] and vulnerabilities[][package][name] returns only publish: gh-failed.
    • Cause: gh's [][key] syntax creates one array element per field, so each field becomes a separate object missing its sibling key. GitHub rejects it with a 422, but the caller never sees it.
    • In lib/publisher.ts (around lines 196-219) gh stderr is piped and only its byte count is kept. The bare code is returned at about lines 200 and 231.
    • Workaround that works: send the body as JSON through bodyFile.

    Suggested fixes:

    1. Surface a sanitized, secret-scanned excerpt of gh stderr (HTTP status and GitHub's error message) in the failure result.
    2. Document in the tool description that arrays of objects need bodyFile.

    Versions: pi 1.5.0, Node v26.8.1, macOS 26.6.2.

  3. woksin commented on Nov 8, 2026

    @woksin
    OwnerAuthor

    The root cause is identified, and there is a working workaround.

    • Cause. addFields in lib/publish-request.ts passes each field as a separate --raw-field/--field. GitHub's gh starts a new array element for every [], so vulnerabilities[][package][ecosystem], vulnerabilities[][package][name] and vulnerabilities[][vulnerable_version_range] become three partial objects instead of one, and the API rejects the request. childFailure in lib/publisher.ts then reports only gh-failed and discards stderr, which hides the HTTP status (see publish: classify capture and gh failures so callers stop retrying blind #151).
    • Workaround (confirmed). Send the whole request as JSON with bodyFile and no fields. That path uses --input with Content-Type: application/json, and the advisory was created successfully. Do not mix fields with bodyFile, because gh then turns the fields into query parameters.
    • Suggested fix. Either document bodyFile as the way to send nested arrays of objects, or add a structured JSON body option for kind: api. Either way, surface a bounded, redacted gh error on failure.
  4. woksin commented on Nov 9, 2026

    @woksin
    OwnerAuthor

    Same failure for PATCH on an existing repository security advisory. kind: api, method: PATCH, endpoint repos/<owner>/<repo>/security-advisories/<ghsa>, fields in gh api nested-array form (vulnerabilities[][package][ecosystem], vulnerabilities[][package][name], vulnerabilities[][vulnerable_version_range], vulnerabilities[][patched_versions]). The result is only publish: gh-failed, with no gh stderr. The publish guard refuses the direct gh api --input <json> route, so updating an advisory's affected/patched version ranges is not possible from an agent session right now. Two things would unblock this: support for a JSON --input body file in kind: api, or including gh's stderr in the failure.

  5. woksin commented on Nov 9, 2026

    @woksin
    OwnerAuthor

    Also reproduced with PATCH repos/<owner>/<repo>/security-advisories/<ghsa> and array fields (vulnerabilities[][package][ecosystem], vulnerabilities[][vulnerable_version_range], vulnerabilities[][patched_versions]): the result is the same opaque gh-failed, with no status code or API message. Editing a draft advisory's affected and patched ranges is therefore impossible through publish too, so the advisory stays a draft until someone sends the request by hand.

  6. woksin commented on Nov 10, 2026

    @woksin
    OwnerAuthor

    Workaround confirmed: publish with kind: api, method: POST, endpoint repos/<owner>/<repo>/security-advisories, and bodyFile pointing at a JSON payload (summary, description, severity, vulnerabilities array) creates the draft advisory. The same request expressed as fields (including vulnerabilities[][package][...] names, with or without a {name, file} description) fails with only gh-failed and no visible detail.

    Remaining fixes:

    • Show gh's stderr text (redacted) or at least the HTTP status in the tool result. A category regex alone hides a 422 validation error.
    • Document in the tool description that nested objects and arrays need a JSON bodyFile, or reject array-style field names up front with that advice.
    • issue-comment with a markdown bodyFile returned payload-unreadable for a freshly written file, while an inline body worked.
  7. woksin commented on Nov 10, 2026

    @woksin
    OwnerAuthor

    Another case of the same opaque failure: release-create with an abbreviated commit SHA as target returns only publish: gh-failed and creates nothing. The same request with the full 40-character SHA succeeds. Either pass through gh's error message, or reject a short SHA target before calling gh with a hint to use the full SHA.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions