🎉 v1.1.0 #13
Reference in New Issue
Block a user
Delete Branch "test"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Style
Chores
Walkthrough
This update removes the custom license and acknowledgements from documentation, refactors proxy handling with a new smart processor for shell scripts, simplifies GitHub URL rewriting, modernizes frontend pages with custom responsive dark mode UI and navigation, replaces the Docker image download UI and service with a new image streaming solution, removes skopeo dependency and related installation steps, and improves concurrency, caching, and rate limiting mechanisms.
Changes
GetConfigto reduce deep copy overhead; removed explicit config load print; suppressed hot reload print message.proxyWithRedirectto use newProcessSmartfor ".sh" files with fallback; direct streaming proxy for others; unified header copying and redirect handling; added global panic recovery middleware; replaced static file route to serve "images.html"; enhanced startup log with host, port, rate limit details; addedinitHealthRoutesfunction.ProcessSmartfor full-content processing with gzip detection and regex URL rewriting; simplified URL transformation logic; removedIsShellFileand related functions.skopeopackage from final Alpine image stage.skopeofrom dependency checks and installation commands; now only checks and installscurlandjq.github.com/gorilla/websocket; movedgolang.org/x/syncto indirect dependency.buildManifestCacheKeyWithPlatformto include platform info in manifest cache keys; removed comments.initDockerProxy; cleaned comments in registry routing and auth options.GetLimiterwith double-checked locking for thread-safe, efficient limiter retrieval and update; removed comments.Cache.Setto remove expired entries first, then bulk delete 25% oldest entries if needed; reused single timestamp for entry creation; removed comments.Sequence Diagram(s)
Poem
📜 Recent review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
8ffceb7f2band118296ee31.📒 Files selected for processing (1)
README.md(1 hunks)🚧 Files skipped from review as they are similar to previous changes (1)
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
🪧 Tips
Chat
There are 3 ways to chat with CodeRabbit:
I pushed a fix in commit <commit_id>, please review it.Explain this complex logic.Open a follow-up GitHub issue for this discussion.@coderabbitaiin a new review comment at the desired location with your query. Examples:@coderabbitai explain this code block.@coderabbitai modularize this function.@coderabbitaiin a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.@coderabbitai read src/utils.ts and explain its main purpose.@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.@coderabbitai help me debug CodeRabbit configuration file.Support
Need help? Create a ticket on our support page for assistance with any issues or questions.
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.
CodeRabbit Commands (Invoked using PR comments)
@coderabbitai pauseto pause the reviews on a PR.@coderabbitai resumeto resume the paused reviews.@coderabbitai reviewto trigger an incremental review. This is useful when automatic reviews are disabled for the repository.@coderabbitai full reviewto do a full review from scratch and review all the files again.@coderabbitai summaryto regenerate the summary of the PR.@coderabbitai generate docstringsto generate docstrings for this PR.@coderabbitai generate sequence diagramto generate a sequence diagram of the changes in this PR.@coderabbitai resolveresolve all the CodeRabbit review comments.@coderabbitai configurationto show the current CodeRabbit configuration for the repository.@coderabbitai helpto get help.Other keywords and placeholders
@coderabbitai ignoreanywhere in the PR description to prevent this PR from being reviewed.@coderabbitai summaryto generate the high-level summary at a specific location in the PR description.@coderabbitaianywhere in the PR title to generate the title automatically.CodeRabbit Configuration File (
.coderabbit.yaml).coderabbit.yamlfile to the root of your repository.# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.jsonDocumentation and Community
Actionable comments posted: 3
🔭 Outside diff range comments (1)
🧹 Nitpick comments (4)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
db9d11a44eanda8498ad24a.📒 Files selected for processing (9)
README.md(0 hunks)src/LICENSE(0 hunks)src/config.go(1 hunks)src/main.go(2 hunks)src/proxysh.go(1 hunks)src/public/index.html(2 hunks)src/public/search.html(24 hunks)src/public/skopeo.html(18 hunks)src/skopeo_service.go(6 hunks)💤 Files with no reviewable changes (2)
🧰 Additional context used
🪛 golangci-lint (1.64.8)
src/skopeo_service.go
172-172: Error return value of
conn.SetReadDeadlineis not checked(errcheck)
187-187: Error return value of
conn.SetReadDeadlineis not checked(errcheck)
200-200: S1000: should use for range instead of for { select {} }
(gosimple)
src/proxysh.go
218-218: SA6002: argument should be pointer-like to avoid allocations
(staticcheck)
🔇 Additional comments (3)
⚠️ Potential issue
Fallback after ProcessSmart may return a truncated file
ProcessSmartconsumesresp.Body.If it returns an error you immediately enter the “direct proxy” branch and
io.Copythe same (now-drained)resp.Body; the client receives an empty / partial response.Fix ideas:
or re-issue the upstream request in the fallback path.
🤖 Prompt for AI Agents
@@ -1,7 +1,7 @@package main⚠️ Potential issue
transformURLdrops the scheme ⇒ generated links become invalidreturn cleanHost + "/" + urlproduces a host-relative URL:Shell tools (
curl,wget) require an explicit scheme; without it they treatthe value as a file path. Fix:
Also consider stripping any existing
https://prefix fromurlonce, soyou never end up with duplicated protocols when the client already supplied
https://….📝 Committable suggestion
🤖 Prompt for AI Agents
🛠️ Refactor suggestion
Concurrent writes to the same WebSocket
startHeartbeatsendsPingframes withc.Conn.WriteMessage, whilewritePumpwrites normal messages.Gorilla WS requires exactly one writer – concurrent writes will panic with “concurrent write to websocket”.
Introduce a dedicated
writeMuinClientand wrap everyWriteMessage/WriteControlcall, or move the ping logic intowritePump.🧰 Tools
🪛 golangci-lint (1.64.8)
200-200: S1000: should use for range instead of for { select {} }
(gosimple)
🤖 Prompt for AI Agents
Actionable comments posted: 5
🧹 Nitpick comments (4)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
e0dbf304e2and80b3f8959f.⛔ Files ignored due to path filters (1)
src/go.sumis excluded by!**/*.sum📒 Files selected for processing (10)
Dockerfile(0 hunks)install-service.sh(2 hunks)src/go.mod(1 hunks)src/imagetar.go(1 hunks)src/main.go(3 hunks)src/public/images.html(1 hunks)src/public/index.html(2 hunks)src/public/search.html(24 hunks)src/public/skopeo.html(0 hunks)src/skopeo_service.go(0 hunks)💤 Files with no reviewable changes (3)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
🔇 Additional comments (3)
⚠️ Potential issue
Include
tarin the installation commandThe script checks for
tarbut does not install it; iftaris missing, the subsequent validation will always fail. Addtarto the apt install list.📝 Committable suggestion
🤖 Prompt for AI Agents
@@ -0,0 +1,932 @@package main⚠️ Potential issue
Batch tar layout is broken
StreamMultipleImagescreates a directory header (image_0_xxx/) but then callsStreamImageToWriter, which writes files at the root of the tar. Subsequent images willproduce duplicate file names and overwrite each other.
Provide the directory prefix to the inner writer (e.g. via
tar.NewWriter(prefixWriter))or change
streamDockerFormatto accept a path prefix.🤖 Prompt for AI Agents
🛠️ Refactor suggestion
Resource leak:
deferinside tight loopdefer layerReader.Close()is executed after the whole function returns, keeping everyuncompressed layer file open until the end. Large images → many FDs, high memory.
Replace with immediate close:
🤖 Prompt for AI Agents
✅ Addressed in commit
03b3c56⚠️ Potential issue
Cache shortcut creates invalid
remote.DescriptorWhen a manifest is pulled from cache you manually craft a
remote.Descriptorwith onlyManifest/MediaType.Methods later invoked (
desc.Image(),desc.ImageIndex()) rely on internal lazy fetchers that are nownil and will panic.
Fix: cache the raw manifest separately but always call
remote.Getto obtain a fulldescriptor, or re-inject the cached bytes through
remote.WithContext+remote.Getusingremote.WithTransport, not by new-struct construction.At minimum populate the remaining fields (
Digest,Size,Descriptor,Client, etc.).🤖 Prompt for AI Agents
✅ Addressed in commit
e305dd2⚠️ Potential issue
Compile-time failure: wrong
DefaultQueryusagec.DefaultQuery("tag")requires a default value parameter (key, defaultValue string).This fails to compile.
📝 Committable suggestion
🤖 Prompt for AI Agents
✅ Addressed in commit
03b3c56Actionable comments posted: 0
♻️ Duplicate comments (2)
🧹 Nitpick comments (1)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
80b3f8959fand03b3c565b9.📒 Files selected for processing (1)
src/imagetar.go(1 hunks)Actionable comments posted: 0
♻️ Duplicate comments (2)
🧹 Nitpick comments (2)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
03b3c565b9ande1920edbd7.📒 Files selected for processing (1)
src/imagetar.go(1 hunks)🧰 Additional context used
🧬 Code Graph Analysis (1)
src/imagetar.go (3)
🔇 Additional comments (1)
Actionable comments posted: 1
🧹 Nitpick comments (2)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
0e7740c391and615aec79e6.📒 Files selected for processing (2)
src/imagetar.go(1 hunks)src/public/images.html(1 hunks)🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/imagetar.go (3)
@@ -0,0 +1,932 @@package main⚠️ Potential issue
Cached descriptor is still incomplete – will panic downstream
Re-creating
remote.Descriptorwith onlyManifestpopulated discards internal fetchers (Client,ref, etc.).Later calls such as
desc.Image()ordesc.ImageIndex()will nil-panic, exactly the issue flagged in a previous review.Please revert to always obtaining the descriptor via
remote.Get, or re-inject the cached bytes throughremote.WithContext/remote.Getinstead of manual struct construction.🤖 Prompt for AI Agents
Actionable comments posted: 2
♻️ Duplicate comments (1)
🧹 Nitpick comments (2)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
615aec79e6and018a8235e2.📒 Files selected for processing (2)
src/imagetar.go(1 hunks)src/token_cache.go(1 hunks)🧰 Additional context used
🧬 Code Graph Analysis (1)
src/imagetar.go (3)
@@ -0,0 +608,4 @@m.Platform.Variant == targetVariant {selectedDesc = &mbreak}🛠️ Refactor suggestion
Variant matching is too strict
If the caller omits a variant (
arm64vsarm64/v8), the equality check fails.Skip the variant comparison when either side is empty to make platform selection more forgiving.
📝 Committable suggestion
🤖 Prompt for AI Agents
@@ -82,0 +75,4 @@if platform == "" {platform = "default"}key := fmt.Sprintf("%s:%s@%s", imageRef, reference, platform)🛠️ Refactor suggestion
Consider key-collision & legacy-cache alignment
Using
"default"whenplatform == ""means the same manifest will now be cached twice (manifest:<hash>andmanifest:<hash-of-…@default>).Either migrate all callers to the new helper or keep the legacy key when
platform == ""to avoid doubled memory and unpredictable cache hits.📝 Committable suggestion
🤖 Prompt for AI Agents
Actionable comments posted: 1
♻️ Duplicate comments (3)
🧹 Nitpick comments (1)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
018a8235e2and8f4fa093c9.📒 Files selected for processing (6)
src/config.go(4 hunks)src/docker.go(1 hunks)src/imagetar.go(1 hunks)src/main.go(5 hunks)src/ratelimiter.go(2 hunks)src/search.go(1 hunks)🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used
🪛 golangci-lint (1.64.8)
src/ratelimiter.go
195-195: SA4006: this value of
entryis never used(staticcheck)
🔇 Additional comments (4)
@@ -193,3 +185,4 @@i.mu.RLock()entry, exists := i.ips[cleanIP]i.mu.RUnlock()⚠️ Potential issue
Remove unused variable assignment to avoid confusion.
The static analysis correctly identifies that the
entryvariable assigned at line 195 is never used because it's shadowed by the redeclaration at line 201. While this doesn't cause a functional issue, it could confuse future maintainers.📝 Committable suggestion
🧰 Tools
🪛 golangci-lint (1.64.8)
195-195: SA4006: this value of
entryis never used(staticcheck)
🤖 Prompt for AI Agents
Actionable comments posted: 1
♻️ Duplicate comments (1)
🧹 Nitpick comments (2)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
8f4fa093c9andfa14a5f5be.📒 Files selected for processing (1)
src/main.go(7 hunks)🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main.go (3)
🔇 Additional comments (1)
@@ -266,0 +333,4 @@checks["config"] = "failed"allReady = false}🛠️ Refactor suggestion
Trusting
X-Forwarded-Hostenables content-injectionrealHostis taken verbatim from the client-controlledX-Forwarded-Host/Hostheader and fed intoProcessSmart, which rewrites GitHub URLs with that value.An attacker can set
X-Forwarded-Host: evil.comand have every rewritten URL point tohttps://evil.com/..., effectively turning the proxy into an open redirect / phishing vector.Sanitise or ignore this header and use a server-side constant (e.g. from config) when rewriting URLs.
[security]
🤖 Prompt for AI Agents
Actionable comments posted: 1
♻️ Duplicate comments (3)
🧹 Nitpick comments (1)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
fa14a5f5beand4756ada922.📒 Files selected for processing (2)
src/imagetar.go(1 hunks)src/main.go(7 hunks)🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/imagetar.go (3)
@@ -0,0 +705,4 @@log.Printf("镜像下载失败: %v", err)c.JSON(http.StatusInternalServerError, gin.H{"error": "镜像下载失败: " + err.Error()})return}🛠️ Refactor suggestion
Cannot send JSON after streaming has begun
If
StreamImageToGin/StreamMultipleImagesalready wrote part of the response body, the subsequentc.JSON(...)call will fail or corrupt output.Instead, log the error and simply abort the context; clients will observe a broken stream.
Also applies to: 767-770
🤖 Prompt for AI Agents
Actionable comments posted: 3
♻️ Duplicate comments (2)
🧹 Nitpick comments (4)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between
4756ada922and8ffceb7f2b.📒 Files selected for processing (14)
README.md(1 hunks)src/access_control.go(2 hunks)src/config.go(2 hunks)src/docker.go(1 hunks)src/imagetar.go(1 hunks)src/main.go(6 hunks)src/proxysh.go(1 hunks)src/public/images.html(1 hunks)src/public/index.html(2 hunks)src/public/search.html(25 hunks)src/ratelimiter.go(4 hunks)src/search.go(1 hunks)src/smart_ratelimit.go(2 hunks)src/token_cache.go(3 hunks)✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (8)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/imagetar.go (3)
🪛 golangci-lint (1.64.8)
src/ratelimiter.go
187-187: SA4006: this value of
entryis never used(staticcheck)
@@ -0,0 +227,4 @@}log.Printf("使用缓存的manifest: %s (平台: %s)", ref.String(), platform)return desc, nil}⚠️ Potential issue
Cached descriptor is still incomplete – will panic downstream
Creating a
remote.Descriptor{ Manifest: … }omits mandatory fields and internal fetchers.Subsequent calls (
desc.Image(),desc.ImageIndex()) nil-panic.Store the raw manifest separately but always obtain a full descriptor via
remote.Get, or hydrate the cached bytes withremote.WithContext+remote.Get. Never hand-craft the struct.🤖 Prompt for AI Agents
⚠️ Potential issue
DOMContentLoaded handler never fires when the script is at page-bottom
Because the script is executed after the DOM is already parsed,
DOMContentLoadedhas already been dispatched and the callback that sets up the modal / domain spans will never run.Call the setup routine immediately (or wrap the whole script in an IIFE) instead of registering a late listener.
🤖 Prompt for AI Agents
🛠️ Refactor suggestion
Remove the first
entryassignment – it’s dead code.entryobtained under the initialRLockis never read because the subsequenti.mu.Lock()block redeclares/shadows it.Drop the redundant read-lock lookup (or return early straight after it) to avoid the SA4006 warning and make the double-checked locking easier to follow.
🧰 Tools
🪛 golangci-lint (1.64.8)
187-187: SA4006: this value of
entryis never used(staticcheck)
🤖 Prompt for AI Agents