Add RFC 9116 security.txt to static/.well-known/ - #599
Conversation
Adds a machine-discoverable security contact at /.well-known/security.txt, served by Hugo from static/. Points to the existing security mailbox (security@lists.valkey.io) and the project's security policy. Includes the RFC 9116-mandatory Expires field. Assisted by an AI tool; every line verified by me against the live site and SECURITY.md. Signed-off-by: Kobi Hikri <kobi.hikri@gmail.com>
📝 WalkthroughWalkthroughChangesSecurity.txt Generation
Suggested reviewers: 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. Comment |
|
| Filename | Overview |
|---|---|
| .github/workflows/zola-deploy.yml | Adds the security.txt generation script to the existing site initialization step. |
| .gitignore | Ignores the generated well-known security.txt file. |
| build/init-security-txt.sh | Generates the security.txt file with contact, expiration, canonical, and policy fields. |
Reviews (2): Last reviewed commit: "Generate security.txt at build time so E..." | Re-trigger Greptile
| Expires: 2027-07-14T00:00:00.000Z | ||
| Preferred-Languages: en | ||
| Canonical: https://valkey.io/.well-known/security.txt | ||
| Policy: https://github.com/valkey-io/valkey/security/policy |
There was a problem hiding this comment.
If GitHub does not expose this repository's security policy through the /security/policy UI route, researchers following the published Policy field can land on a missing or generic page instead of the actual disclosure policy. The site already links its security policy directly to the repository SECURITY.md, so using that same target avoids a broken policy reference in security.txt.
|
Per review: derive the RFC 9116 Expires field from the build rather than committing a fixed date, so it always sits one year past the last site build. - add build/init-security-txt.sh, following the existing build/ script style - call it from the same workflow step as init-topics-and-clients and init-commands - gitignore the generated file, matching how content/commands and content/topics are handled Signed-off-by: Kobi Hikri <kobi.hikri@gmail.com>
|
Both points taken, @stockholmux — thanks, and you were right on the first one. 1. Not Hugo. My PR description said Hugo twice; this is a Zola site ( 2. The static expiry. Agreed, and fixed in 8ba6721 — it's now derived from the build instead of committed:
One note on mechanism, since you said "use a template": I looked at doing this as a Zola template first, but Zola only emits templated output at fixed paths it knows about ( Also worth flagging honestly: the script branches on GNU vs BSD Disclosure: I used AI assistance (Claude Opus 5) in preparing this. I verified the generator against this repo's conventions and ran it myself, and I take responsibility for it. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@build/init-security-txt.sh`:
- Around line 24-40: Make build/init-security-txt.sh fail immediately when any
generation command fails by enabling strict shell options after argument
validation, including set -euo pipefail. Ensure failures from date, mkdir, or
the security.txt heredoc prevent the script from completing successfully.
- Around line 24-27: Update the date calculation in init-security-txt.sh to use
a fixed interval of 364 days in both the GNU date and BSD date branches,
replacing the current calendar-year shift. Keep the existing UTC timestamp
format and platform detection intact so Expires remains strictly under one year.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 74ec2c39-b2c4-49f3-b90f-17d45144f560
📒 Files selected for processing (3)
.github/workflows/zola-deploy.yml.gitignorebuild/init-security-txt.sh
| if date -u -d '+1 year' >/dev/null 2>&1; then | ||
| EXPIRES=$(date -u -d '+1 year' +%Y-%m-%dT%H:%M:%SZ) # GNU date | ||
| else | ||
| EXPIRES=$(date -u -v+1y +%Y-%m-%dT%H:%M:%SZ) # BSD date |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file context =="
sed -n '1,80p' build/init-security-txt.sh 2>/dev/null || true
echo
echo "== RFC references in repo =="
rg -n "rfc9116|Expires|security.txt|policy.txt" .
echo
echo "== date semantics for one year vs days =="
python3 - <<'PY'
import datetime
for start in ["2023-02-28", "2024-02-28", "2024-12-31", "2025-02-28", "2025-01-01"]:
d = datetime.date.fromisoformat(start)
one = d + datetime.timedelta(days=366)
years = d.replace(year=2026) if d.month == d.month and d.day == d.day else None
print(f"{start}: +366d={one.isoformat()} days={366}, next-cm=2026-02-28")
PY
tmp="$(mktemp -d)"
if command -v date >/dev/null; then
echo "== date behavior on this system =="
printf '%s ' 'GNU/BSD date is:'
date -u -v+1y +%Y-%m-%dT%H:%M:%SZ >/dev/null 2>&1 && echo "BSD" || echo "not BSD"
date -u -d '+1 day' +%Y-%m-%dT%H:%M:%SZ >/dev/null 2>&1 && echo "GNU" || echo "not GNU"
for base in 2023-02-28 2024-02-28 2024-12-31 2025-02-28; do
d=$(TZ=UTC date -d "$base" +%s)
echo "----- base $base (epoch $d) -----"
date -u -d "@$((d + 366*86400))" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || true
date -u -d "+1 year" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || true
done
else
echo "no date command"
fi
rm -rf "$tmp"Repository: valkey-io/valkey-io.github.io
Length of output: 2976
🌐 Web query:
RFC 9116 security.txt Expires field recommended expiration less than one year
💡 Result:
RFC 9116 explicitly recommends that the "Expires" field in a security.txt file be set to a date and time less than one year in the future [1][2]. This recommendation is intended to help prevent the use of stale information [1][2]. Because inaccurate or outdated security contact information can result in security reports being lost or misdirected—potentially leaving vulnerabilities exposed—the standard emphasizes the importance of keeping the information current [2]. The "Expires" field serves as a mechanism to signal to security researchers when the information in the file is no longer considered valid [1][2]. The field is mandatory and must appear exactly once in the file [1][2].
Citations:
Keep Expires strictly below one year.
RFC 9116 recommends security.txt expirations less than one year in the future. +1 year can be 366 days across a leap year; use a fixed interval such as +364 days instead of a calendar year shift.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@build/init-security-txt.sh` around lines 24 - 27, Update the date calculation
in init-security-txt.sh to use a fixed interval of 364 days in both the GNU date
and BSD date branches, replacing the current calendar-year shift. Keep the
existing UTC timestamp format and platform detection intact so Expires remains
strictly under one year.
Source: MCP tools
| if date -u -d '+1 year' >/dev/null 2>&1; then | ||
| EXPIRES=$(date -u -d '+1 year' +%Y-%m-%dT%H:%M:%SZ) # GNU date | ||
| else | ||
| EXPIRES=$(date -u -v+1y +%Y-%m-%dT%H:%M:%SZ) # BSD date | ||
| fi | ||
|
|
||
| mkdir -p "$WELL_KNOWN" | ||
|
|
||
| cat > "${WELL_KNOWN}/security.txt" <<EOF | ||
| # Valkey security contact — see https://github.com/valkey-io/valkey/security/policy | ||
| # Generated at build time by build/init-security-txt.sh — do not edit by hand. | ||
| Contact: mailto:security@lists.valkey.io | ||
| Expires: ${EXPIRES} | ||
| Preferred-Languages: en | ||
| Canonical: https://valkey.io/.well-known/security.txt | ||
| Policy: https://github.com/valkey-io/valkey/security/policy | ||
| EOF |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Fail the build when generation fails.
Without set -e or explicit status checks, a failed date, mkdir, or cat can be followed by the successful echo, causing .github/workflows/zola-deploy.yml Line 65 to continue with a missing or invalid security.txt.
Add set -euo pipefail after argument validation, or check each command explicitly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@build/init-security-txt.sh` around lines 24 - 40, Make
build/init-security-txt.sh fail immediately when any generation command fails by
enabling strict shell options after argument validation, including set -euo
pipefail. Ensure failures from date, mkdir, or the security.txt heredoc prevent
the script from completing successfully.
| Expires: ${EXPIRES} | ||
| Preferred-Languages: en | ||
| Canonical: https://valkey.io/.well-known/security.txt | ||
| Policy: https://github.com/valkey-io/valkey/security/policy |
There was a problem hiding this comment.
The generated security.txt still points Policy at GitHub's /security/policy UI route. If that route is unavailable or renders a generic page instead of the repository policy, researchers following the published policy link can miss the disclosure instructions even though the repository has a concrete SECURITY.md document.
| Policy: https://github.com/valkey-io/valkey/security/policy | |
| Policy: https://github.com/valkey-io/valkey/blob/unstable/SECURITY.md |
Artifacts
Repro: security.txt generation output showing indirect Policy line
- The full command output behind this check.
Repro: Policy line verification script
- Evidence file captured while the check ran.
Repro: Policy line assertion output
- The full command output behind this check.
Repro: HTTP comparison script for generated and concrete policy URLs
- Evidence file captured while the check ran.
Repro: HTTP status and response trace for generated and concrete policy URLs
- The full command output behind this check.
What this does
Adds
/.well-known/security.txtto the site by placing it instatic/.well-known/security.txt, which Hugo copies verbatim to the published site root.Why
RFC 9116 defines a small, standard file at
/.well-known/security.txtso a security researcher can find where to report a vulnerability without guessing. Right now the live file is missing:The project already has a security contact — I just pointed the file at the existing mailbox and policy rather than inventing anything:
Contact: mailto:security@lists.valkey.io(fromSECURITY.mdin this repo)Policy: https://github.com/valkey-io/valkey/security/policyExpires:— RFC 9116 requires this field; I set it ~1 year out.Verifying it will serve
static/is already served verbatim — for examplestatic/img/IconGithub.svgis live athttps://valkey.io/img/IconGithub.svg(200). Hugo copies dot-directories understatic/too, sostatic/.well-known/security.txtwill publish athttps://valkey.io/.well-known/security.txt. Please double-check on a preview build.Single file, no other changes. Commit is DCO signed-off.
Disclosure: I used an AI tool to help spot this and draft the file. I verified every line myself against the live site and this repo's
SECURITY.md, and I take responsibility for the change. Happy to adjust theExpiresdate, contact, or policy link to whatever the maintainers prefer.