Skip to content

feat: favicon from logo-icon.svg — all required sizes, ICO + PNG (Closes #471)#673

Closed
LaphoqueRC wants to merge 1 commit intoSolFoundry:mainfrom
LaphoqueRC:feat/favicon-v4
Closed

feat: favicon from logo-icon.svg — all required sizes, ICO + PNG (Closes #471)#673
LaphoqueRC wants to merge 1 commit intoSolFoundry:mainfrom
LaphoqueRC:feat/favicon-v4

Conversation

@LaphoqueRC
Copy link
Copy Markdown
Contributor

Changes

Generates proper favicons from assets/logo-icon.svg in all required sizes and formats, with all assets committed for immediate browser use.

What's included

File Purpose
assets/favicons/favicon.ico Multi-size ICO (16×16 + 32×32 embedded)
assets/favicons/apple-touch-icon.png 180×180 Apple Touch Icon
assets/favicons/favicon-192x192.png 192×192 PNG for PWA / Android
assets/favicons/favicon-512x512.png 512×512 PNG for PWA splash
assets/favicons/site.webmanifest PWA manifest with purpose: any + maskable on both icon entries
index.html <head> updated with all favicon link tags + theme-color meta
scripts/generate-favicons.sh Regeneration script (ImageMagick 6 + 7 compatible)
scripts/test-favicons.sh 28 assertions covering files, sizes, HTML refs, manifest, script

Acceptance Criteria

  • Favicon generated in: 16×16, 32×32 (in ICO), 180×180, 192×192, 512×512
  • Both .ico and .png formats
  • site.webmanifest updated with icon references + purpose metadata
  • HTML <head> updated with all favicon <link> tags + theme-color
  • Favicon visible in browser tab (assets committed, no build step needed)
  • Binary file count: 4 (under the 5-file limit)
  • Tests: 28 passing assertions

Binary Count

4 binary files committed (favicon.ico + 3 PNGs). Well under the 5-file auto-rejection threshold.


Wallet: HZV6YPdTeJPjPujWjzsFLLKja91K2Ze78XeY8MeFhfK8

Generated directly from assets/logo-icon.svg using rsvg-convert + ImageMagick.
4 binary files committed (under the 5-file limit):
- favicon.ico (multi-size: 16x16 + 32x32 embedded)
- apple-touch-icon.png (180x180)
- favicon-192x192.png (192x192)
- favicon-512x512.png (512x512)

Also includes:
- site.webmanifest with 'purpose' metadata (any + maskable) on both icon sizes
- index.html <head> updated with all favicon link tags + theme-color meta
- scripts/generate-favicons.sh — regeneration script, supports ImageMagick 6 (convert) and 7 (magick)
- scripts/test-favicons.sh — 28 assertions covering files, sizes, HTML refs, manifest content, script quality

Wallet: HZV6YPdTeJPjPujWjzsFLLKja91K2Ze78XeY8MeFhfK8
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 22, 2026

📝 Walkthrough

Walkthrough

This pull request adds favicon asset support and web app manifest configuration to the repository. A new Web App Manifest JSON file defines the application's name, description, start URL, display mode, colors, and icon references. The index.html head is updated with favicon link tags (ICO, multiple PNG sizes, Apple touch icon, and web manifest) pointing to the new favicon assets. Two new Bash scripts are added: one to generate the favicon PNG and ICO files from an existing SVG logo source using rsvg-convert and ImageMagick, and another to validate the presence and structure of all favicon assets and HTML/manifest references.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • Issue #471: This PR directly implements the core requirements—generating favicons from logo-icon.svg in multiple sizes and formats (ICO, 192×192 PNG, 512×512 PNG, apple-touch-icon), creating a web app manifest, and updating HTML with favicon references—fulfilling the bounty objectives.
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Title check ✅ Passed The title clearly and specifically describes the main change: generating favicons from logo-icon.svg in all required sizes and formats, with specific mention of ICO and PNG formats and closure of issue #471.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, detailing all included files, their purposes, acceptance criteria met, and implementation details about the favicon generation.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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: 4

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

Inline comments:
In `@assets/favicons/site.webmanifest`:
- Around line 16-21: site.webmanifest currently reuses the same PNG for both
"purpose": "any" and "purpose": "maskable" which risks background clipping on
masked displays; regenerate or produce maskable-specific PNGs from
assets/logo-icon.svg that either remove or extend/flatten the background to
accommodate circular/masked crops, update the manifest entries for the maskable
sizes (the entries with "purpose": "maskable") to point to those new files, and
verify the result using a preview tool like Maskable.app to ensure no important
background gradients or edges are lost.

In `@index.html`:
- Around line 9-10: The two link elements that declare type="image/png" but
reference /assets/favicons/favicon.ico are a MIME mismatch; fix by either
changing the type attribute on those link tags to image/x-icon to match the .ico
file (update the link elements with href="/assets/favicons/favicon.ico"
accordingly) or (if you want separate PNG assets) update the favicon generation
script to preserve/output favicon-16x16.png and favicon-32x32.png and change the
hrefs to those PNG filenames while keeping type="image/png"; remove
duplicate/incorrect tags if you choose to rely solely on the ICO.

In `@scripts/generate-favicons.sh`:
- Around line 39-40: The script currently writes to predictable temp paths
(/tmp/_favicon-16.png, /tmp/_favicon-32.png and similarly at the later
rsvg-convert calls), which is vulnerable to symlink/race attacks; change the
logic so you create secure temporary files with mktemp (e.g. TMP_16=$(mktemp)
and TMP_32=$(mktemp)), use those variables in the rsvg-convert invocations
(references: the rsvg-convert commands and the /tmp/_favicon-*.png names), and
ensure you register a trap to remove the temp files on exit to avoid leaks.

In `@scripts/test-favicons.sh`:
- Around line 58-61: Remove the conditional guards and make the size assertions
unconditional: call assert_min_size for each favicon path (favicon.ico,
apple-touch-icon.png, favicon-192x192.png, favicon-512x512.png) without the
leading [[ -f ... ]] &&. Update the assert_min_size function to detect a missing
file (using the same existence logic as assert_file) and fail the test with a
clear message when the file does not exist, and keep its existing size check
behavior otherwise; reference assert_min_size and the FAVICONS variable to
locate the changes and remove the guarded calls currently surrounding those four
filename checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1b0c6f12-ccfe-46a0-8656-73ecb79c3334

📥 Commits

Reviewing files that changed from the base of the PR and between 8924119 and d6bb378.

⛔ Files ignored due to path filters (4)
  • assets/favicons/apple-touch-icon.png is excluded by !**/*.png
  • assets/favicons/favicon-192x192.png is excluded by !**/*.png
  • assets/favicons/favicon-512x512.png is excluded by !**/*.png
  • assets/favicons/favicon.ico is excluded by !**/*.ico
📒 Files selected for processing (4)
  • assets/favicons/site.webmanifest
  • index.html
  • scripts/generate-favicons.sh
  • scripts/test-favicons.sh

Comment on lines +16 to +21
{
"src": "/assets/favicons/favicon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if logo-icon.svg exists and inspect its viewBox to assess padding
if [[ -f "assets/logo-icon.svg" ]]; then
  echo "=== SVG viewBox and dimensions ==="
  grep -oP '(viewBox|width|height)="[^"]*"' assets/logo-icon.svg | head -5
  echo ""
  echo "=== Manual check needed: verify icon content has ~10% padding for maskable safe zone ==="
else
  echo "logo-icon.svg not found at expected path"
fi

Repository: SolFoundry/solfoundry

Length of output: 261


🏁 Script executed:

#!/bin/bash
# Examine the SVG content to assess padding and visual element placement
echo "=== SVG Content (first 50 lines) ==="
head -50 assets/logo-icon.svg

echo ""
echo "=== Checking favicon files referenced in manifest ==="
ls -la assets/favicons/ | grep -E "(png|svg)"

echo ""
echo "=== Checking webmanifest for icon paths ==="
grep -A 3 '"src"' assets/favicons/site.webmanifest

Repository: SolFoundry/solfoundry

Length of output: 3092


Maskable icons may have suboptimal background clipping—verify PNG generation handles this properly.

The same PNG files are used for both purpose: "any" and purpose: "maskable" (lines 16-21 and 28-33). The source SVG (assets/logo-icon.svg) shows the background gradient extends to the full 512×512 canvas edges, which will be clipped when Android masks the icon to circular or other shapes.

The main anvil/hammer icon content is centered and has adequate padding, but the background treatment may result in visual issues on devices that apply masking. Verify that:

  1. The PNG generation process accounts for maskable clipping, or
  2. Create separate maskable-specific variants that either remove the background or ensure it handles masking gracefully
  3. Use a tool like Maskable.app to preview the actual display
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@assets/favicons/site.webmanifest` around lines 16 - 21, site.webmanifest
currently reuses the same PNG for both "purpose": "any" and "purpose":
"maskable" which risks background clipping on masked displays; regenerate or
produce maskable-specific PNGs from assets/logo-icon.svg that either remove or
extend/flatten the background to accommodate circular/masked crops, update the
manifest entries for the maskable sizes (the entries with "purpose": "maskable")
to point to those new files, and verify the result using a preview tool like
Maskable.app to ensure no important background gradients or edges are lost.

Comment on lines +9 to +10
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon.ico">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

MIME type mismatch: type="image/png" but href points to .ico file.

Lines 9-10 declare type="image/png" but reference favicon.ico, which is an ICO file (image/x-icon). This semantic mismatch may cause browsers to incorrectly interpret the resource or fail to use it.

The generation script (generate-favicons.sh) creates temporary 16×16 and 32×32 PNGs only to embed them into the ICO, then deletes them. If you want separate PNG link tags for these sizes, the script should preserve those files, or these lines should be removed/corrected to avoid the type mismatch.

Options:

  1. Remove lines 9-10 entirely (rely on the ICO which already embeds both sizes)
  2. Change type to image/x-icon to match the actual file type
  3. Update the generation script to output separate favicon-16x16.png and favicon-32x32.png files and reference those here
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@index.html` around lines 9 - 10, The two link elements that declare
type="image/png" but reference /assets/favicons/favicon.ico are a MIME mismatch;
fix by either changing the type attribute on those link tags to image/x-icon to
match the .ico file (update the link elements with
href="/assets/favicons/favicon.ico" accordingly) or (if you want separate PNG
assets) update the favicon generation script to preserve/output
favicon-16x16.png and favicon-32x32.png and change the hrefs to those PNG
filenames while keeping type="image/png"; remove duplicate/incorrect tags if you
choose to rely solely on the ICO.

Comment on lines +39 to +40
rsvg-convert -w 16 -h 16 "$SOURCE_SVG" -o /tmp/_favicon-16.png
rsvg-convert -w 32 -h 32 "$SOURCE_SVG" -o /tmp/_favicon-32.png
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Insecure use of predictable temp file paths in shared /tmp directory.

Using hardcoded paths like /tmp/_favicon-16.png and /tmp/_favicon-32.png in a shared directory creates a symlink race condition vulnerability. In multi-user environments, an attacker could pre-create a symlink at these paths pointing to a sensitive file, causing the script to overwrite it when run by another user.

Use mktemp to create secure temporary files:

🔒 Proposed fix using mktemp
+# Create secure temp directory
+TMPDIR=$(mktemp -d)
+trap 'rm -rf "$TMPDIR"' EXIT
+
 # ── PNG sizes ────────────────────────────────────────────────────────────────
 
-rsvg-convert -w 16  -h 16  "$SOURCE_SVG" -o /tmp/_favicon-16.png
-rsvg-convert -w 32  -h 32  "$SOURCE_SVG" -o /tmp/_favicon-32.png
+rsvg-convert -w 16  -h 16  "$SOURCE_SVG" -o "$TMPDIR/favicon-16.png"
+rsvg-convert -w 32  -h 32  "$SOURCE_SVG" -o "$TMPDIR/favicon-32.png"
 rsvg-convert -w 180 -h 180 "$SOURCE_SVG" -o "$OUT_DIR/apple-touch-icon.png"
 rsvg-convert -w 192 -h 192 "$SOURCE_SVG" -o "$OUT_DIR/favicon-192x192.png"
 rsvg-convert -w 512 -h 512 "$SOURCE_SVG" -o "$OUT_DIR/favicon-512x512.png"
 # ── Multi-size ICO (embeds 16x16 + 32x32) ────────────────────────────────────
 
-"$IMAGEMAGICK_CMD" /tmp/_favicon-16.png /tmp/_favicon-32.png "$OUT_DIR/favicon.ico"
-rm -f /tmp/_favicon-16.png /tmp/_favicon-32.png
+"$IMAGEMAGICK_CMD" "$TMPDIR/favicon-16.png" "$TMPDIR/favicon-32.png" "$OUT_DIR/favicon.ico"
+# Cleanup handled by trap

Also applies to: 51-52

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/generate-favicons.sh` around lines 39 - 40, The script currently
writes to predictable temp paths (/tmp/_favicon-16.png, /tmp/_favicon-32.png and
similarly at the later rsvg-convert calls), which is vulnerable to symlink/race
attacks; change the logic so you create secure temporary files with mktemp (e.g.
TMP_16=$(mktemp) and TMP_32=$(mktemp)), use those variables in the rsvg-convert
invocations (references: the rsvg-convert commands and the /tmp/_favicon-*.png
names), and ensure you register a trap to remove the temp files on exit to avoid
leaks.

Comment on lines +58 to +61
[[ -f "$FAVICONS/favicon.ico" ]] && assert_min_size "$FAVICONS/favicon.ico" 1024 "favicon.ico is non-trivial (≥1KB)"
[[ -f "$FAVICONS/apple-touch-icon.png" ]] && assert_min_size "$FAVICONS/apple-touch-icon.png" 5000 "apple-touch-icon.png is non-trivial (≥5KB)"
[[ -f "$FAVICONS/favicon-192x192.png" ]] && assert_min_size "$FAVICONS/favicon-192x192.png" 5000 "favicon-192x192.png is non-trivial (≥5KB)"
[[ -f "$FAVICONS/favicon-512x512.png" ]] && assert_min_size "$FAVICONS/favicon-512x512.png" 20000 "favicon-512x512.png is non-trivial (≥20KB)"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider unconditional size assertions for clearer test failure reporting.

The pattern [[ -f "$file" ]] && assert_min_size ... silently skips size checks if files are missing. While assert_file above catches missing files, if a file is deleted between checks (unlikely but possible), or if someone reorders tests, the size check would be silently skipped without incrementing FAIL.

For more explicit test behavior, consider always calling assert_min_size and having it handle the missing file case internally:

♻️ Optional: Handle missing files in assert_min_size
 assert_min_size() {
   local size
+  if [[ ! -f "$1" ]]; then
+    echo "  ✗ $3 — file not found: $1"
+    ((FAIL++)) || true
+    return
+  fi
   size=$(wc -c < "$1" 2>/dev/null || echo 0)

Then remove the [[ -f ... ]] && guards on lines 58-61.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/test-favicons.sh` around lines 58 - 61, Remove the conditional guards
and make the size assertions unconditional: call assert_min_size for each
favicon path (favicon.ico, apple-touch-icon.png, favicon-192x192.png,
favicon-512x512.png) without the leading [[ -f ... ]] &&. Update the
assert_min_size function to detect a missing file (using the same existence
logic as assert_file) and fail the test with a clear message when the file does
not exist, and keep its existing size check behavior otherwise; reference
assert_min_size and the FAVICONS variable to locate the changes and remove the
guarded calls currently surrounding those four filename checks.

@LaphoqueRC LaphoqueRC closed this Mar 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant