diff --git a/.well-known/security.txt b/.well-known/security.txt index 747cf42..8660ffe 100644 --- a/.well-known/security.txt +++ b/.well-known/security.txt @@ -4,3 +4,6 @@ Expires: 2027-12-31T00:00:00.000Z Preferred-Languages: ru, en Canonical: https://gl.mhspx.su/.well-known/security.txt Policy: https://gl.mhspx.su/security + +# Этот файл отдаётся по адресу /.well-known/security.txt: копия для сборки +# лежит в web/public/.well-known/security.txt и должна совпадать с этой. diff --git a/Makefile b/Makefile index 26d70d6..7896f08 100644 --- a/Makefile +++ b/Makefile @@ -142,18 +142,29 @@ generate: tools ## Проверить сгенерированные артеф else echo "==> sqlc: запросов пока нет, пропускаем"; fi .PHONY: security -security: tools ## AppSec: govulncheck, gitleaks, trivy (по возможности) +security: tools ## AppSec: govulncheck, gitleaks, npm audit, trivy (по возможности) @mkdir -p $(BUILD_DIR) @echo "==> govulncheck" @govulncheck ./cmd/... ./internal/... || { echo "govulncheck нашёл уязвимости"; exit 1; } @echo "==> gitleaks" @$(ROOT)/scripts/gitleaks-scan.sh + @echo "==> npm audit (web, только production-зависимости)" + @cd $(WEB_DIR) && npm audit --omit=dev --audit-level=high || { echo "npm audit нашёл уязвимости"; exit 1; } @echo "==> trivy filesystem scan" @if command -v trivy >/dev/null 2>&1; then \ trivy fs --quiet --scanners vuln,secret,misconfig --exit-code 1 \ --skip-dirs .cache --skip-dirs .git --skip-dirs web/node_modules .; \ else echo "trivy not installed — skipped"; fi +.PHONY: sbom +sbom: ## SBOM зависимостей в build/sbom.cdx.json (trivy, если установлен) + @mkdir -p $(BUILD_DIR) + @if command -v trivy >/dev/null 2>&1; then \ + trivy fs --quiet --format cyclonedx --output $(BUILD_DIR)/sbom.cdx.json \ + --skip-dirs .cache --skip-dirs web/node_modules . && \ + echo "SBOM: $(BUILD_DIR)/sbom.cdx.json"; \ + else echo "trivy не установлен — SBOM не собран (запустите на сервере сборки)"; fi + .PHONY: secrets-scan secrets-scan: tools ## Только проверка на утечки секретов @$(ROOT)/scripts/gitleaks-scan.sh diff --git a/internal/server/static.go b/internal/server/static.go index 29f6d38..4c77775 100644 --- a/internal/server/static.go +++ b/internal/server/static.go @@ -63,6 +63,10 @@ func staticContentType(rel string) string { return "text/css; charset=utf-8" case ".svg": return "image/svg+xml" + case ".txt": + // security.txt (RFC 9116): в минимальном alpine-окружении mime может + // не знать расширение и отдать октет-поток. + return "text/plain; charset=utf-8" } return mime.TypeByExtension(filepath.Ext(rel)) } diff --git a/web/public/.well-known/security.txt b/web/public/.well-known/security.txt new file mode 100644 index 0000000..8660ffe --- /dev/null +++ b/web/public/.well-known/security.txt @@ -0,0 +1,9 @@ +# Политика безопасности glchat (RFC 9116) +Contact: mailto:security@gl.mhspx.su +Expires: 2027-12-31T00:00:00.000Z +Preferred-Languages: ru, en +Canonical: https://gl.mhspx.su/.well-known/security.txt +Policy: https://gl.mhspx.su/security + +# Этот файл отдаётся по адресу /.well-known/security.txt: копия для сборки +# лежит в web/public/.well-known/security.txt и должна совпадать с этой.