Skip to content

fix(base): preserve attachment metadata on base uploads#563

Merged
kongenpei merged 6 commits intomainfrom
fix-attachment-size
Apr 20, 2026
Merged

fix(base): preserve attachment metadata on base uploads#563
kongenpei merged 6 commits intomainfrom
fix-attachment-size

Conversation

@kongenpei
Copy link
Copy Markdown
Collaborator

@kongenpei kongenpei commented Apr 20, 2026

Summary

This PR fixes Base attachment uploads so newly uploaded files preserve attachment metadata when the CLI patches the record cell.

What Changed

  • include size in the attachment payload written back by base +record-upload-attachment
  • include mime_type in that payload as well
  • detect MIME type from the local file name and content when building the attachment object
  • extend Base shortcut tests to assert metadata is preserved for both single-part and multipart uploads

Root Cause

The upload step returned a file_token, but the subsequent Base record patch rebuilt the new attachment item with only file_token and name. That dropped size and mime_type, which then showed up as missing or incorrect metadata in the web UI.

Impact

Base attachment uploads from the CLI now keep the same essential metadata that downstream UI and automation expect:

  • text files keep mime_type: text/plain
  • large multipart uploads keep their real byte size
  • newly uploaded attachments behave consistently with existing attachment items in the same cell

Validation

  • make unit-test
  • go vet ./...
  • gofmt -l .
  • go mod tidy with no go.mod / go.sum diff
  • go test ./shortcuts/base -run 'TestBaseRecordExecute/upload attachment' -v
  • live verification against Base records with:
    • 21 MiB multipart upload preserving size
    • text file upload preserving mime_type: text/plain

Notes

  • go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=origin/main currently fails in this environment with:
    • main.go:1: : error obtaining VCS status: exit status 128

Summary by CodeRabbit

  • New Features

    • Attachment uploads now include MIME type and file size metadata; dry-run output shows these fields.
    • MIME detection prefers filename extension, falls back to source path extension, then to content-based detection for common formats and plain text; defaults to application/octet-stream.
  • Tests

    • Added comprehensive MIME-detection tests (extensions, content, error paths) and tightened dry-run/test assertions to require mime_type and size.
  • Bug Fixes

    • Improved background refresh synchronization to avoid flaky timing issues.

@kongenpei kongenpei requested a review from zgz2048 April 20, 2026 04:16
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

Adds extension-first then content-based MIME detection for attachments, includes mime_type and size in the attachment metadata sent to Base and dry-run output, updates upload logic to surface read errors, and tightens tests to validate these fields and detection behaviors.

Changes

Cohort / File(s) Summary
Test Assertions
shortcuts/base/base_execute_test.go, shortcuts/base/base_dryrun_ops_test.go
Tightened tests to require mime_type and size in attachment PATCH payloads and dry-run outputs for small-file and multipart upload cases.
Upload + MIME Logic
shortcuts/base/record_upload_attachment.go
Added detectAttachmentMIMEType and helpers: extension-first lookup (strip params), content-based detection (inspect first 512 bytes for PNG/JPEG/GIF/WEBP/PDF or UTF-8/printable text), default to application/octet-stream; include mime_type and size in payload/returned attachment; propagate file-read errors.
MIME Detection Tests
shortcuts/base/record_upload_attachment_test.go
New tests with in-memory fileio.File/FileInfo fixtures covering filename-extension detection, source-path fallback, content-based detection (table-driven magic-number and text/binary cases), and error wrapping for file access failures.
Registry sync in tests
internal/registry/remote.go, internal/registry/remote_test.go
Added a WaitGroup to track background refresh goroutine and waitForBackgroundRefresh(); tests now wait for background refresh completion before resetting package-level state, removing fixed sleeps.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Upload as uploadAttachmentToBase()
    participant Detect as detectAttachmentMIMEType()
    participant FS as FileSystem
    participant Base as Base API

    Client->>Upload: initiate attachment upload
    Upload->>Detect: ask MIME (fileName, filePath, file)
    Detect->>Detect: strip params, check extension
    alt extension yields MIME
        Detect-->>Upload: return MIME
    else extension unknown
        Detect->>FS: read first 512 bytes
        FS-->>Detect: return bytes or error
        alt read successful
            Detect->>Detect: check magic numbers / text heuristic
            Detect-->>Upload: return inferred MIME or application/octet-stream
        else read error
            Detect-->>Upload: return wrapped read error
        end
    end
    Upload->>Upload: build metadata {file_token, name, size, mime_type}
    Upload->>Base: PATCH record-upload-attachment with metadata
    Base-->>Upload: respond with attachment data
    Upload-->>Client: return attachment info
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • zgz2048

Poem

🐰 I sniff file names, then peek inside,
Extensions first, then bytes decide.
I count the size, declare the type,
Patch it tidy, done just right.
A hopping rabbit logs each stripe. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The PR description follows the template with complete Summary, Changes, Test Plan, and Related Issues sections, providing clear context and validation details.
Title check ✅ Passed The PR title accurately describes the main change: preserving attachment metadata (size and mime_type) on Base uploads, which is the core focus across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-attachment-size

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added domain/base PR touches the base domain size/M Single-domain feat or fix with limited business impact labels Apr 20, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 92.00000% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.24%. Comparing base (1262aac) to head (8ec6441).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/base/record_upload_attachment.go 92.00% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #563      +/-   ##
==========================================
+ Coverage   60.19%   60.24%   +0.04%     
==========================================
  Files         390      390              
  Lines       33433    33482      +49     
==========================================
+ Hits        20125    20170      +45     
- Misses      11426    11428       +2     
- Partials     1882     1884       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@kongenpei kongenpei marked this pull request as ready for review April 20, 2026 04:39
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
shortcuts/base/record_upload_attachment.go (2)

109-113: ⚠️ Potential issue | 🟡 Minor

Keep dry-run PATCH metadata in sync.

The real upload now patches mime_type and size, but dry-run still shows only file_token, name, and deprecated_set_attachment for the uploaded item. This makes the user-facing dry-run output stale.

🛠️ Proposed dry-run payload update
 				map[string]interface{}{
 					"file_token":                "<uploaded_file_token>",
 					"name":                      fileName,
+					"mime_type":                 "<detected_mime_type>",
+					"size":                      "<file_size>",
 					"deprecated_set_attachment": true,
 				},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/base/record_upload_attachment.go` around lines 109 - 113, The
dry-run PATCH metadata in shortcuts/base/record_upload_attachment.go is missing
the mime_type and size fields that the real upload now patches; update the
dry-run map literal (the uploaded item metadata map containing "file_token",
"name", "deprecated_set_attachment") to include "mime_type" and "size" with
appropriate placeholder values (e.g., "<mime/type>" and a numeric placeholder or
the size variable) so the dry-run output matches the real upload payload.

249-279: ⚠️ Potential issue | 🟠 Major

Detect MIME before performing the upload.

detectAttachmentMIMEType runs after UploadDriveMediaAll / UploadDriveMediaMultipart. If the post-upload read fails, the command returns an error after the non-idempotent upload already succeeded, leaving uploaded media unattached to the Base record. Fail fast before upload instead.

🛠️ Proposed ordering fix
 func uploadAttachmentToBase(runtime *common.RuntimeContext, filePath, fileName, baseToken string, fileSize int64) (map[string]interface{}, error) {
+	mimeType, err := detectAttachmentMIMEType(runtime.FileIO(), filePath, fileName)
+	if err != nil {
+		return nil, err
+	}
+
 	parentNode := baseToken
 	var (
 		fileToken string
-		err       error
 	)
 	if fileSize <= common.MaxDriveMediaUploadSinglePartSize {
 		fileToken, err = common.UploadDriveMediaAll(runtime, common.DriveMediaUploadAllConfig{
@@
 	if err != nil {
 		return nil, err
 	}
-
-	mimeType, err := detectAttachmentMIMEType(runtime.FileIO(), filePath, fileName)
-	if err != nil {
-		return nil, err
-	}
 
 	attachment := map[string]interface{}{
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/base/record_upload_attachment.go` around lines 249 - 279, In
uploadAttachmentToBase, detectAttachmentMIMEType is called after the
non-idempotent UploadDriveMediaAll/UploadDriveMediaMultipart calls, which can
leave orphaned uploads if the post-read fails; move the
detectAttachmentMIMEType(runtime.FileIO(), filePath, fileName) call to before
selecting/performing the upload (i.e., call it at the top of
uploadAttachmentToBase and return any error immediately), then proceed to call
UploadDriveMediaAll or UploadDriveMediaMultipart with the confirmed MIME; keep
the same parameters and error handling for
UploadDriveMediaAll/UploadDriveMediaMultipart and ensure any early error aborts
before any upload is attempted.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shortcuts/base/record_upload_attachment_test.go`:
- Around line 99-104: The test only checks the binary fallback for
detectAttachmentMIMEFromContent; add a table-driven subtest in
TestDetectAttachmentMIMEFromContentBinaryFallback (or rename to
TestDetectAttachmentMIMEFromContent) that enumerates cases for PNG, JPEG, GIF,
WEBP, PDF, empty content, text (printable bytes), control-byte text
(non-printable ASCII), and the binary fallback, each with input byte slices and
expected MIME strings, and iterate with t.Run for each case asserting
detectAttachmentMIMEFromContent returns the expected value so all signature
branches are covered.

---

Outside diff comments:
In `@shortcuts/base/record_upload_attachment.go`:
- Around line 109-113: The dry-run PATCH metadata in
shortcuts/base/record_upload_attachment.go is missing the mime_type and size
fields that the real upload now patches; update the dry-run map literal (the
uploaded item metadata map containing "file_token", "name",
"deprecated_set_attachment") to include "mime_type" and "size" with appropriate
placeholder values (e.g., "<mime/type>" and a numeric placeholder or the size
variable) so the dry-run output matches the real upload payload.
- Around line 249-279: In uploadAttachmentToBase, detectAttachmentMIMEType is
called after the non-idempotent UploadDriveMediaAll/UploadDriveMediaMultipart
calls, which can leave orphaned uploads if the post-read fails; move the
detectAttachmentMIMEType(runtime.FileIO(), filePath, fileName) call to before
selecting/performing the upload (i.e., call it at the top of
uploadAttachmentToBase and return any error immediately), then proceed to call
UploadDriveMediaAll or UploadDriveMediaMultipart with the confirmed MIME; keep
the same parameters and error handling for
UploadDriveMediaAll/UploadDriveMediaMultipart and ensure any early error aborts
before any upload is attempted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2b0cbca4-3a0b-45e1-90d4-b82956f557d0

📥 Commits

Reviewing files that changed from the base of the PR and between 9acd121 and df3d3a9.

📒 Files selected for processing (3)
  • shortcuts/base/base_execute_test.go
  • shortcuts/base/record_upload_attachment.go
  • shortcuts/base/record_upload_attachment_test.go

Comment thread shortcuts/base/record_upload_attachment_test.go Outdated
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 20, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@8ec64411704974a0503a3791ca28821c14dc441e

🧩 Skill update

npx skills add larksuite/cli#fix-attachment-size -y -g

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shortcuts/base/record_upload_attachment.go`:
- Around line 292-308: detectAttachmentMIMEType currently only checks the
extension of fileName (via mime.TypeByExtension(filepath.Ext(fileName))) before
content sniffing, which misses cases where fileName has no extension but
filePath does; update detectAttachmentMIMEType to, after the existing fileName
extension check fails, try mime.TypeByExtension on
strings.ToLower(filepath.Ext(filePath)) (trimmed and passed through
stripMIMEParams) and return that if non-empty before opening/reading the file;
keep existing error handling on fio.Open, reading into buf and falling back to
detectAttachmentMIMEFromContent if no extension-derived MIME is found.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 09be3f2b-01b2-49b7-97c9-6e1217a019d4

📥 Commits

Reviewing files that changed from the base of the PR and between df3d3a9 and cae8ef9.

📒 Files selected for processing (3)
  • shortcuts/base/base_dryrun_ops_test.go
  • shortcuts/base/record_upload_attachment.go
  • shortcuts/base/record_upload_attachment_test.go
✅ Files skipped from review due to trivial changes (1)
  • shortcuts/base/record_upload_attachment_test.go

Comment thread shortcuts/base/record_upload_attachment.go
@kongenpei kongenpei changed the title fix: preserve attachment metadata on base uploads fix(base): preserve attachment metadata on base uploads Apr 20, 2026
@kongenpei kongenpei merged commit cd66642 into main Apr 20, 2026
21 checks passed
@kongenpei kongenpei deleted the fix-attachment-size branch April 20, 2026 11:14
@liangshuo-1 liangshuo-1 mentioned this pull request Apr 20, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/base PR touches the base domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants