**The action.** `hound hygiene` and `hound supply-chain` only ever saw repositories somebody had already cloned onto a machine with Hound installed. action/ runs them on every push and pull request: it installs the published .deb, verifies it against the same signed checksum the desktop agent uses, and annotates findings on the lines of the files they concern so a reviewer sees them in the diff rather than in a log nobody opens. report.py will not print a credential it found — GitHub masks only values registered as secrets, so anything else in an annotation is readable by everyone who can see the run and stays in the API afterwards. And it will not report a partial scan as clean: a history walk that hits its limit says so, because "no findings" and "no findings in the part we looked at" mean different things to somebody deciding whether to merge. **The background.** A radial gradient was set on `html, body` — both, each 100% tall — so it painted twice and the seam between the two layers appeared as a band across the middle of the page when scrolled. It was also a hardcoded near-black the light theme had no way to override. Three more like it: the active tab, button hover, and the log panel. The ground is a token now, and every colour in the stylesheet comes from one, so no rule can put one theme's text on the other's background. **The palette.** The light theme now uses houndav.com's values exactly — #5A58C8 buttons, #147A3D, #9A6100, #C22222 — so the app and the site are recognisably the same product rather than two guesses at it. Then measured rather than assumed, and found two failures Joe had not mentioned: "faint" text was 2.90:1 in dark and 3.37:1 in light, and the dark button hover was 4.41:1. All three now clear 4.5:1, and all eight text pairs pass WCAG AA in both themes. **And four more places still naming ClamAV**, which has not been the engine for a long time: the auto-update caption said the daemon runs freshclam, the update log said the same, an error suggested `apt install clamav`, and a permissions hint pointed at /var/lib/clamav. The engine swap replaced the code and left the copy describing software this product no longer runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
88 lines
3 KiB
YAML
88 lines
3 KiB
YAML
name: 'Hound Security Scan'
|
|
description: 'Find exposed credentials, malicious dependencies and unsafe CI in a repository'
|
|
author: 'Hound Antivirus'
|
|
branding:
|
|
icon: 'shield'
|
|
color: 'purple'
|
|
|
|
inputs:
|
|
path:
|
|
description: 'Directory to scan, relative to the repository root'
|
|
required: false
|
|
default: '.'
|
|
history:
|
|
description: 'Also walk git history for credentials that were removed but not revoked'
|
|
required: false
|
|
default: 'false'
|
|
fail-on:
|
|
description: 'Fail the job at this severity or above: critical | warning | never'
|
|
required: false
|
|
default: 'critical'
|
|
annotate:
|
|
description: 'Annotate the affected files in the diff view'
|
|
required: false
|
|
default: 'true'
|
|
version:
|
|
description: 'Hound version to use, or "latest"'
|
|
required: false
|
|
default: 'latest'
|
|
|
|
outputs:
|
|
critical:
|
|
description: 'Number of critical findings'
|
|
value: ${{ steps.scan.outputs.critical }}
|
|
warnings:
|
|
description: 'Number of warnings'
|
|
value: ${{ steps.scan.outputs.warnings }}
|
|
report:
|
|
description: 'Path to the JSON report'
|
|
value: ${{ steps.scan.outputs.report }}
|
|
|
|
runs:
|
|
using: 'composite'
|
|
steps:
|
|
- id: install
|
|
shell: bash
|
|
# Verified against the same signed manifest the desktop agent uses, so
|
|
# a compromised download host cannot substitute a different binary here
|
|
# any more than it can there.
|
|
run: |
|
|
set -euo pipefail
|
|
want='${{ inputs.version }}'
|
|
if [ "$want" = latest ]; then
|
|
want="$(curl -fsSL https://dl.houndav.com/latest.json | python3 -c 'import json,sys;print(json.load(sys.stdin)["release"]["version"])')"
|
|
fi
|
|
url="https://dl.houndav.com/deb/hound_${want}_amd64.deb"
|
|
curl -fsSL "$url" -o /tmp/hound.deb
|
|
expected="$(curl -fsSL "${url}.sha256")"
|
|
actual="$(sha256sum /tmp/hound.deb | cut -d' ' -f1)"
|
|
if [ "$expected" != "$actual" ]; then
|
|
echo "::error::the Hound download does not match its published checksum"
|
|
exit 1
|
|
fi
|
|
sudo apt-get install -y -qq /tmp/hound.deb >/dev/null
|
|
echo "installed hound $want"
|
|
|
|
- id: scan
|
|
shell: bash
|
|
working-directory: ${{ github.workspace }}
|
|
run: |
|
|
set -uo pipefail
|
|
args=""
|
|
if [ '${{ inputs.history }}' = 'true' ]; then args="--history"; fi
|
|
|
|
# Two reports: the supply-chain sweep and the hygiene checks. They
|
|
# share a finding shape, so the outputs merge cleanly.
|
|
hound hygiene '${{ inputs.path }}' $args --json > /tmp/hygiene.json || true
|
|
hound supply-chain '${{ inputs.path }}' --json > /tmp/supply.json 2>/dev/null || true
|
|
|
|
python3 "$GITHUB_ACTION_PATH/report.py" \
|
|
--hygiene /tmp/hygiene.json \
|
|
--supply /tmp/supply.json \
|
|
--annotate '${{ inputs.annotate }}' \
|
|
--fail-on '${{ inputs.fail-on }}' \
|
|
--summary "${GITHUB_STEP_SUMMARY:-/dev/null}" \
|
|
--out /tmp/hound-report.json
|
|
status=$?
|
|
echo "report=/tmp/hound-report.json" >> "$GITHUB_OUTPUT"
|
|
exit $status
|