A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
atcr.io
docker
container
atproto
go
1# README Embedding Feature
2
3## Overview
4
5Enhance the repository page (`/r/{handle}/{repository}`) with embedded README content fetched from the source repository, similar to Docker Hub's "Overview" tab.
6
7## Current State
8
9The repository page currently shows:
10- Repository metadata from OCI annotations
11- Short description from `org.opencontainers.image.description`
12- External links to source (`org.opencontainers.image.source`) and docs (`org.opencontainers.image.documentation`)
13- Tags and manifests lists
14
15## Proposed Feature
16
17Automatically fetch and render README.md content from the source repository when available, displaying it in an "Overview" section on the repository page.
18
19## Implementation Approach
20
21### 1. Source URL Detection
22
23Parse `org.opencontainers.image.source` annotation to detect GitHub repositories:
24- Pattern: `https://github.com/{owner}/{repo}`
25- Extract owner and repo name
26
27### 2. README Fetching
28
29Fetch README.md from GitHub via raw content URL:
30```
31https://raw.githubusercontent.com/{owner}/{repo}/{branch}/README.md
32```
33
34Try multiple branch names in order:
351. `main`
362. `master`
373. `develop`
38
39Fallback if README not found or fetch fails.
40
41### 3. Markdown Rendering
42
43Use a Go markdown library to render README content:
44- **Option A**: `github.com/gomarkdown/markdown` - Pure Go, fast
45- **Option B**: `github.com/yuin/goldmark` - CommonMark compliant, extensible
46- **Option C**: Call GitHub's markdown API (requires network call)
47
48Recommended: `goldmark` for CommonMark compliance and GitHub-flavored markdown support.
49
50### 4. Caching Strategy
51
52Cache rendered README to avoid repeated fetches:
53
54**Option A: In-memory cache**
55- Simple, fast
56- Lost on restart
57- Good for MVP
58
59**Option B: Database cache**
60- Add `readme_html` column to `manifests` table
61- Update on new manifest pushes
62- Persistent across restarts
63- Background job to refresh periodically
64
65**Option C: Hybrid**
66- Cache in database
67- Also cache in memory for frequently accessed repos
68- TTL-based refresh (e.g., 1 hour)
69
70### 5. UI Integration
71
72Add "Overview" section to repository page:
73- Show after repository header, before tags/manifests
74- Render markdown as HTML
75- Apply CSS styling for markdown elements (headings, code blocks, tables, etc.)
76- Handle images in README (may need to proxy or allow external images)
77
78## Implementation Steps
79
801. **Add README fetcher** (`pkg/appview/readme/fetcher.go`)
81 ```go
82 type Fetcher struct {
83 httpClient *http.Client
84 cache Cache
85 }
86
87 func (f *Fetcher) FetchGitHubReadme(sourceURL string) (string, error)
88 func (f *Fetcher) RenderMarkdown(content string) (string, error)
89 ```
90
912. **Update database schema** (optional, for caching)
92 ```sql
93 ALTER TABLE manifests ADD COLUMN readme_html TEXT;
94 ALTER TABLE manifests ADD COLUMN readme_fetched_at TIMESTAMP;
95 ```
96
973. **Update RepositoryPageHandler**
98 - Fetch README for repository
99 - Pass rendered HTML to template
100
1014. **Update repository.html template**
102 - Add "Overview" section
103 - Render HTML safely (use `template.HTML`)
104
1055. **Add markdown CSS**
106 - Style headings, code blocks, lists, tables
107 - Syntax highlighting for code blocks (optional)
108
109## Security Considerations
110
1111. **XSS Prevention**
112 - Sanitize HTML output from markdown renderer
113 - Use `bluemonday` or similar HTML sanitizer
114 - Only allow safe HTML elements and attributes
115
1162. **Rate Limiting**
117 - Cache aggressively to avoid hitting GitHub rate limits
118 - Consider GitHub API instead of raw content (requires token but higher limits)
119 - Handle 429 responses gracefully
120
1213. **Image Handling**
122 - README may contain images with relative URLs
123 - Options:
124 - Rewrite image URLs to absolute GitHub URLs
125 - Proxy images through ATCR (caching, security)
126 - Block external images (simplest, but breaks many READMEs)
127
1284. **Content Size**
129 - Limit README size (e.g., 1MB max)
130 - Truncate very long READMEs with "View on GitHub" link
131
132## Future Enhancements
133
1341. **Support other platforms**
135 - GitLab: `https://gitlab.com/{owner}/{repo}/-/raw/{branch}/README.md`
136 - Gitea/Forgejo
137 - Bitbucket
138
1392. **Custom README upload**
140 - Allow users to upload custom README via UI
141 - Store in PDS as `io.atcr.readme` record
142 - Priority: custom > source repo
143
1443. **Automatic updates**
145 - Background job to refresh READMEs periodically
146 - Webhook support to update on push to source repo
147
1484. **Syntax highlighting**
149 - Use highlight.js or similar for code blocks
150 - Support multiple languages
151
152## Example Flow
153
1541. User pushes image with label: `org.opencontainers.image.source=https://github.com/alice/myapp`
1552. Manifest stored with source URL annotation
1563. User visits `/r/alice/myapp`
1574. RepositoryPageHandler:
158 - Checks cache for README
159 - If not cached or expired:
160 - Fetches `https://raw.githubusercontent.com/alice/myapp/main/README.md`
161 - Renders markdown to HTML
162 - Sanitizes HTML
163 - Caches result
164 - Passes README HTML to template
1655. Template renders Overview section with README content
166
167## Dependencies
168
169```go
170// Markdown rendering
171github.com/yuin/goldmark v1.6.0
172github.com/yuin/goldmark-emoji v1.0.2 // GitHub emoji support
173
174// HTML sanitization
175github.com/microcosm-cc/bluemonday v1.0.26
176```
177
178## References
179
180- [OCI Image Spec - Annotations](https://github.com/opencontainers/image-spec/blob/main/annotations.md)
181- [Docker Hub Overview tab behavior](https://hub.docker.com/)
182- [Goldmark documentation](https://github.com/yuin/goldmark)
183- [GitHub raw content URLs](https://raw.githubusercontent.com/)