Skip to content

Plugin client does not handle the request-public stanza #9

Description

@pscheid92

Summary

The plugin client (HandleCommonStanza in Age/Recipients/PluginRecipient.cs and Age/Recipients/PluginIdentity.cs) handles the msg, request-secret, and confirm interactive stanzas, but not request-public, which the age-plugin protocol defines. A request-public stanza currently falls through to default and is answered with unsupported, so any plugin that asks the user for a non-secret value fails.

Spec

Per the C2SP age-plugin spec:

(request-public; MESSAGE) - the plugin requires some public string from the user in order to progress.

  • Response is (ok; REQUESTED_PUBLIC) or (fail).

It appears in both the recipient (phase 2) and identity (phase 2) state machines, i.e. it should be handled in both PluginRecipient and PluginIdentity.

The reference implementation (FiloSottile/age plugin/client.go) handles it alongside request-secret, distinguishing the two by type:

case "request-secret", "request-public":
    if c.RequestValue == nil {
        return true, writeStanza(conn, "fail")
    }
    secret, err := c.RequestValue(name, string(s.Body), s.Type == "request-secret")
    ...
    return true, writeStanzaWithBody(conn, "ok", []byte(secret))

Why this should be small

The plumbing already exists:

  • IPluginCallbacks.RequestValue(string prompt, bool secret) already carries the secret flag — request-public is just the secret: false case.
  • The CLI callback (AgeCommand.CliPluginCallbacks.RequestValue) already implements the non-secret path (echoed Console.ReadLine), so no UI work is needed.

Suggested change:

  • Add request-public to the existing no-callbacks guard so it replies fail when no callbacks are wired.
  • Add a case "request-public": that calls callbacks!.RequestValue(prompt, secret: false) and writes ok with the returned value.
  • Add test coverage in PluginTests.cs for both the recipient and identity paths (value returned, and fail when no callbacks).

Context

Spotted while fixing the confirm command (#6). Deferred from that PR to keep it scoped to the confirm bug; this is a pre-existing gap, not a regression.

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