feat: add attachments command for download and inspection#121
Merged
Conversation
Add a top-level `attachments` command group (aliases `attachment`, `a`) so users and agents can download and inspect Redmine attachments without dropping to `redmine api` plus a manual curl with a hand-extracted key. - `attachments get <id>`: metadata in table/json/csv. - `attachments download <id>`: stream the file to disk (-d/--dir, --path, --path - for stdout, default ./<filename>). Reuses the active profile's auth and streams rather than buffering the whole file in memory. - `issues get <id> --attachments`: list an issue's attachments with their IDs; `--download-attachments <dir>`: download all of them at once. - Surface attachments on the typed Issue model (CLI and MCP get_issue). - New read-only MCP tool `get_attachment`. Security: only attach credentials to the configured server host, so the API key and basic-auth are never leaked to an off-site host if the server or an attachment content_url redirects to external object storage. Update the bundled skill to tell the agent to download and inspect attachments (especially images), plus docs in English and Chinese, and unit and e2e tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
There is currently no convenient way to download a Redmine attachment through the CLI. Users have to fetch metadata with
redmine api /attachments/<id>.jsonto find thecontent_url, thencurlit with a hand-extracted API key (becauseredmine apionly prints text/JSON and can't stream binary). This PR makes attachment retrieval a one-liner that reuses the CLI's existing auth, profile handling, and server config.What's new
New
attachmentscommand group (aliasesattachment,a):redmine attachments get <id>— print attachment metadata intable/json/csv.redmine attachments download <id>— download the file, authenticating with the active profile (no curl, no manual key).-d/--dir <dir>saves into a directory under the real filename.--path <file>saves to an exact path;--path -streams to stdout../<filename>in the current directory.Attachment discoverability on
issues get:--attachmentslists the issue's attachments (id, filename, size, content type) so you can immediately download one.--download-attachments <dir>downloads every attachment of the issue into<dir>in one step.Supporting changes:
Issuemodel, soinclude=attachmentsworks for both the CLI and MCPget_issue(consolidated the previously wiki-onlyAttachmenttype).get_attachment.Flag-naming note
The original proposal suggested
-o <path>/-o -fordownload, but-o/--outputis the global output-format flag across this CLI. To avoid overloading it, the destination is controlled by--dir/--path(the proposal explicitly allowed distinct names), and-okeeps its usual meaning —downloadrespects-o jsonto emit a structured result object describing the saved file. This is documented in--helpand the docs.Security
While implementing the download path I found (and fixed) a credential-leak vector: the API key was attached to every request hop, so a server or
content_urlthat 302-redirects off-site (e.g. to external object storage) would leak the key to that host.authTransportnow only attaches credentials (API key or basic auth) when the request targets the configured server host. This protects all request paths, not just downloads, and still follows legitimate redirects. Covered by tests, including an end-to-end cross-host redirect reproduction.Docs & skill
Attachmentscommand page in English and Simplified Chinese, plus sidebar entry.issues getpage (both languages) for the new flags.Tests
issues get --download-attachments.Verification
gofmtclean,golangci-lint0 issues,go vetclean, all unit tests pass, e2e compiles, docs site builds, MCP codegen and golden in sync.