Skip to content

POC: Add Grype vulnerability scanning#111

Open
cwage wants to merge 164 commits intomasterfrom
add-grype-scanning
Open

POC: Add Grype vulnerability scanning#111
cwage wants to merge 164 commits intomasterfrom
add-grype-scanning

Conversation

@cwage
Copy link
Copy Markdown
Owner

@cwage cwage commented Feb 3, 2026

Proof-of-concept for container image vulnerability scanning using Grype.

Changes

  • Add docker-compose.grype.yml - runs Grype scanner via Docker
  • Add scripts/grype-compose.sh - scans all images in a compose file
  • Add Makefile targets:
    • make grype IMAGE=<img> - scan a single image
    • make grype-compose - scan all production images
    • make grype-pull - pull the scanner image
  • Update README with usage examples

Status

This is a proof-of-concept. The scanning works locally, but CI integration and notification/reporting is not yet implemented.

See #110 for discussion on notification approach (ntfy.sh).

Test Plan

make grype IMAGE=nginx:latest
make grype-compose
make grype-compose GRYPE_ARGS="--fail-on critical"

cwage and others added 30 commits November 19, 2025 18:05
Add Debian cloud image download for Proxmox
Add Ansible role to build Proxmox templates
adding screeshot key and fixing a tinyfugue issue
misc improvements and specifying in AGENTS that we will only ever use one bridge interface likely
- Added portanas (10.10.15.4:5344) to inventory
- Created synology_nfs role for managing NFS shares via SSH/CLI
- Added Makefile targets: nas, nas-check, nas-discover
- Discovery mode captures current shares, NFS exports, users, groups
- Uses ansible.builtin.raw module (like OpenBSD firewall role)
- Documented Synology-specific gotchas in README:
  - synogroup --member replaces ALL members (not additive)
  - Deploy user shell and group membership can be reset by DSM
  - Full setup instructions for deploy user with sudo access

Technical notes:
- SSH on port 5344 (non-standard)
- Synology commands in /usr/syno/sbin/
- Deploy user requires administrators group for sudo access
- Raw module avoids Python permission issues on DSM

Related: #14
- Create shares using synoshare --add command
- Manage NFS exports via Ansible-controlled block in /etc/exports
- Use systemctl for DSM 7 service management (not old synoservice)
- Idempotent share creation with inline shell check
- Reload exports with exportfs -ra after changes

Implementation details:
- Combined check/create into single raw task to avoid SSH connection issues
- Uses heredoc without quotes to allow $(date) expansion in comments
- Configured pve-backups and pve-templates shares for Proxmox
- Both shares exported to 10.10.15.0/24 with no_root_squash

Technical notes:
- DSM 7 uses systemctl instead of synoservice/synoservicecfg
- NFS service is nfs-server.service
- synoshare creates shares DSM recognizes and manages
- /etc/exports may be regenerated by DSM during updates (re-run playbook)

Synology documentation added to docs/syn/ for reference.

Successfully tested - created both shares and configured NFS exports.

Related: #14
Changes based on GitHub Copilot review comments on PR #18:

**Fixed idempotency check (shares.yml):**
- Added explicit 'SHARE_CREATED' marker to share creation script
- Updated changed_when to check for marker instead of parsing output
- More reliable than trying to interpret synoshare output

**Implemented nfs_enabled field:**
- Added when condition to respect nfs_enabled flag per share
- Defaults to true for backward compatibility
- Allows selectively disabling shares without removing from config

**Made anonuid/anongid configurable:**
- Added role defaults: nfs_default_anonuid (1025), nfs_default_anongid (100)
- Template now supports override at rule/share/role level
- Maintains Synology defaults while allowing customization

**Fixed exports template formatting:**
- Added explicit newline before END ANSIBLE MANAGED BLOCK marker
- Ensures marker appears on its own line in /etc/exports

**Updated documentation:**
- Changed synoshare --list to --enum ALL (actual implementation)
- Added note that --enum is undocumented DSM 7 command
- Updated CLI reference with more complete command examples
- Added explanation of discovery command usage

**Added tofu template variable:**
- pm_template_id variable for VM template ID (default 9000)
- Used during test VM provisioning

All review threads resolved and marked as resolved on PR #18.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
adding a role for nfs mounts
adding nfs mounts to proxmox and rearranging make targets/playbooks to make more sense
fixing clippy's retardation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
cleaning up dhcpd.conf template
cwage and others added 25 commits January 13, 2026 22:33
Add vs-cwage Vintage Story server profile and gunsmoke nginx site
…mplating

- Set vs-buttopia active with 49 mods (Terra Prety, Rivers, expanded foods, etc.)
- Add world_config support to serverconfig.json.j2 template
- Configure worldgen settings (landcover, oceanscale, landformScale)
- Mark vs-sloths and vs-cwage as inactive (archived)
- Remove old CarryOnConfig.json
- Use boolean true instead of string 'true' for harshWinters/snowAccum defaults
- Use unquoted numeric/boolean values in gaming_servers.yml
Reactivate vs-buttopia with new modpack and fix WorldConfiguration templating
Disable temporal storms for vs-buttopia
Adds cloudflared container to expose Jellyfin securely without opening
firewall ports. Tunnel token is retrieved from OpenBao and deployed via
ansible to /opt/stacks/.env.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Pin cloudflared to version 2026.1.2 instead of :latest
- Use compose profiles to make cloudflared opt-in (only starts when token present)
- Add | default('') to token reference to handle missing field gracefully
- Update warning message to reflect that container will be skipped, not crash-loop

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Cloudflare Tunnel for external Jellyfin access
- Merge Video and Music NFS shares into single Media share (rw)
- Switch from jellyfin/jellyfin to linuxserver/jellyfin:10.11.6
- Enables consistent PUID/PGID handling and write access for arr stack

Part of #101
Consolidate NAS mounts and switch Jellyfin to LinuxServer image
- Add SABnzbd (linuxserver/sabnzbd:4.5.5) for Usenet downloads
- Add Radarr (linuxserver/radarr:6.0.4) for movie automation
- Add Sonarr (linuxserver/sonarr:4.0.16) for TV automation
- Add DNS entries for sabnzbd, radarr, sonarr
- Add post-deploy task to configure SABnzbd host whitelist
- All services use PUID/PGID 1000, Traefik for HTTPS

Closes #101
- Check if SABnzbd container is running before attempting config
- Check for presence of each hostname instead of exact line match
- Append missing hostnames instead of overwriting entire whitelist
Add Radarr/Sonarr/SABnzbd arr stack for media automation
Migrate paperless-ngx from NAS to containers VM:
- Add NFS mount for /mnt/paperless from NAS share
- Add paperless + redis services to docker-compose with Traefik
- Add DNS CNAME for paperless.lan.quietlife.net

Closes #104

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Address Copilot review feedback:
- Pin redis to 8.0.5 instead of major version tag
- Pin paperless-ngx to 2.20.6 instead of :latest

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migrate paperless-ngx from NAS to containers VM
Configure automated dependency update checks for:
- OpenTofu providers (weekly)
- Production container images in docker-compose stack (weekly)
- Development/build Dockerfiles (monthly)
- Lego ACME client container (weekly)
Add Dependabot configuration for dependency updates
Bumps [trufflesecurity/trufflehog](https://github.com/trufflesecurity/trufflehog) from 3.79.0 to 3.92.5.
- [Release notes](https://github.com/trufflesecurity/trufflehog/releases)
- [Commits](trufflesecurity/trufflehog@v3.79.0...v3.92.5)

---
updated-dependencies:
- dependency-name: trufflesecurity/trufflehog
  dependency-version: 3.92.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Dependabot's docker ecosystem only scans Dockerfile files, not
docker-compose.yml. Remove /ansible/files/stacks and /lego directories
since they only contain compose files and were failing scans.
Fix Dependabot config: remove compose-only directories
…trufflehog-3.92.5

Bump trufflesecurity/trufflehog from 3.79.0 to 3.92.5
Adds make targets for scanning container images with Grype:
- `make grype IMAGE=<img>` - scan a single image
- `make grype-compose` - scan all images in production compose file
- `make grype-pull` - pull the grype scanner image

Related to #110 - notification/reporting integration TBD.
Copilot AI review requested due to automatic review settings February 3, 2026 23:51
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds Grype vulnerability scanning capability to the homelab repository as a proof-of-concept. It integrates the Anchore Grype container scanner for detecting CVEs in Docker images used in the production stack.

Changes:

  • Add Docker Compose service for running Grype scanner with cached vulnerability database
  • Add shell script to scan all images referenced in a compose file
  • Add Makefile targets for scanning single images, all production images, and pulling the scanner image
  • Update README with usage examples and documentation

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
docker-compose.grype.yml Defines Grype scanner service with Docker socket access and database caching
scripts/grype-compose.sh Shell script to extract and scan all images from a compose file
Makefile Add targets for grype, grype-compose, and grype-pull with proper error handling
README.md Document new scanning commands and provide usage examples

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/grype-compose.sh
echo ""

FAILED=0
for IMAGE in $IMAGES; do
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The unquoted variable $IMAGES in the for loop relies on word splitting which could fail if image names contain spaces or special characters. While uncommon in practice for Docker images, this violates shellcheck best practices. Consider using an array or proper quoting. For example:

while IFS= read -r IMAGE; do
    # loop body
done <<< "$IMAGES"

Or use an array:

mapfile -t IMAGES_ARRAY <<< "$IMAGES"
for IMAGE in "${IMAGES_ARRAY[@]}"; do
    # loop body
done

Copilot uses AI. Check for mistakes.
Comment thread scripts/grype-compose.sh
echo ">>> Scanning: $IMAGE"
echo "----------------------------------------"

if docker compose -f docker-compose.grype.yml run --rm grype "$IMAGE" "$@"; then
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The script assumes it's run from the repository root since it references docker-compose.grype.yml without a path. If run from a different directory, it will fail. Consider making the script location-aware by using the script's directory to locate the compose file, or document in the usage comment that it must be run from the repository root.

Copilot uses AI. Check for mistakes.
Comment thread scripts/grype-compose.sh
@@ -0,0 +1,53 @@
#!/bin/bash
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

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

The shebang should use #!/usr/bin/env bash for consistency with other scripts in the repository. The scripts at scripts/install-precommit-hook.sh, ansible/scripts/install-precommit-hook.sh, and tofu/scripts/install-precommit-hook.sh all use #!/usr/bin/env bash, which is more portable as it uses the PATH to locate bash rather than assuming it's at /bin/bash.

Copilot uses AI. Check for mistakes.
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.

2 participants