ソースを参照

Fix R01-N16, doc R01-N17: composer-audit helper + admin-manual cadence note

R01-N16 — add `bin/audit.sh`, a thin wrapper around `composer audit
--locked` that runs inside the project's runtime image so the audit
reflects the exact dependency tree the live container ships. Operators
get a one-line tool to surface known CVEs in the locked PhpSpreadsheet
chain (a long history of XML-related advisories), and a recommended
weekly-cron snippet in the admin manual. Image lookup honours
`SPRINT_PLANER_IMAGE`. Baseline run today: "No security vulnerability
advisories found."

admin-manual §5.5 grows a "Composer dependency cadence" block with the
recommended rebuild rhythm (after every git pull, monthly minimum) and
the audit-script invocation + cron stanza.

R01-N17 — accept-by-design. The library `jumbojett/openid-connect-php`
stores its `state` and PKCE `code_verifier` in `$_SESSION` under fixed
keys, so two parallel sign-in tabs clobber each other's state. The
failure mode is purely cosmetic: the older tab gets bounced to
/?auth_error=1 and the user retries — the OIDC state-mismatch is the
correct rejection. New admin-manual §5.6 documents the one-tab-at-a-
time rule so operators are not surprised.

No code change for R01-N17; the SPEC + REVIEW_01 status block lands in
the next docs commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chiappa 2 日 前
コミット
ef9b9b865c
2 ファイル変更71 行追加0 行削除
  1. 35 0
      bin/audit.sh
  2. 36 0
      doc/admin-manual.md

+ 35 - 0
bin/audit.sh

@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+# R01-N16 — surface known CVEs in the locked composer dependencies.
+#
+# Runs `composer audit` against composer.lock inside the project's runtime
+# image, so the audit reflects the exact versions the running container
+# has. Intended for periodic operator use (e.g. weekly cron) and as a
+# pre-deploy gate after `git pull`.
+#
+# Exit status mirrors composer's: 0 = clean, non-zero = advisories found
+# (or composer itself errored). Operators can pipe to `mail` / `wall` etc.
+
+set -euo pipefail
+
+# Resolve repo root so the script works regardless of cwd.
+SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
+REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." &>/dev/null && pwd)"
+cd "${REPO_ROOT}"
+
+IMAGE="${SPRINT_PLANER_IMAGE:-sprint_planer_web-app:latest}"
+
+if ! command -v docker >/dev/null 2>&1; then
+    echo "audit.sh: docker is required (composer + the right ext-* set live in the image)" >&2
+    exit 2
+fi
+
+if ! docker image inspect "${IMAGE}" >/dev/null 2>&1; then
+    echo "audit.sh: image '${IMAGE}' not found locally — run 'docker compose build' first" >&2
+    exit 2
+fi
+
+exec docker run --rm \
+    -v "${REPO_ROOT}:/app" \
+    -w /app \
+    "${IMAGE}" \
+    sh -c "git config --global --add safe.directory /app && composer audit --locked --no-interaction"

+ 36 - 0
doc/admin-manual.md

@@ -427,6 +427,42 @@ Schema migrations under `migrations/` run automatically on the next
 request after restart. Always take a backup of `./data/app.sqlite`
 before pulling.
 
+**Composer dependency cadence (R01-N16).** The XLSX import wizard is
+backed by [PhpSpreadsheet](https://github.com/PHPOffice/PhpSpreadsheet),
+which has a long history of XML-related advisories. The `composer.json`
+caret range (`^3.4`) lets minor upgrades land on each `docker compose
+build --no-cache`, but the operator is responsible for rebuilding
+promptly when a new release ships. Recommended cadence: rebuild after
+any `git pull`, and at minimum monthly even on a quiet branch. Run the
+auditor to surface known CVEs in the currently locked versions:
+
+```bash
+./bin/audit.sh
+# → "No security vulnerability advisories found." when clean.
+# → exit 1 + a vulnerability table when an advisory matches.
+```
+
+The script wraps `composer audit --locked` inside the runtime image so
+the audit reflects the exact dependency tree the live container runs.
+A weekly cron is a low-friction option:
+
+```cron
+# /etc/cron.d/sprint-planner-audit
+0 7 * * 1  www-data  cd /opt/sprint-planer-web && ./bin/audit.sh \
+                       || mail -s 'sprint-planer composer advisory' admin@example.com
+```
+
+### 5.6 Tabbed sign-in note (R01-N17)
+
+The OIDC handshake stores its `state` and PKCE `code_verifier` in the
+PHP session under fixed keys. If you start a sign-in flow in two
+browser tabs at the same time, the second tab overwrites the first
+tab's state — when you finish the first tab, the callback rejects the
+state mismatch and you are bounced back to `/?auth_error=1`. This is
+not a security issue (the rejection is the correct OIDC behaviour),
+but it can be confusing. **Complete one sign-in at a time**, or close
+the older tab before starting a fresh login.
+
 ---
 
 ## 6. Troubleshooting