You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by ar...@apache.org on 2026/09/15 14:23:12 UTC
(tooling-trusted-releases) branch arm updated (7ae57745 -> 5e8c6459)
This is an automated email from the ASF dual-hosted git repository.
alitheg pushed a change to branch arm
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
discard 7ae57745 #1067 - add freshness check for npm dependencies
new 5e8c6459 #1067 - add freshness check for npm dependencies
This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version. This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:
* -- * -- B -- O -- O -- O (7ae57745)
\
N -- N -- N refs/heads/arm (5e8c6459)
You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.
Any revisions marked "omit" are not gone; other references still
refer to them. Any revisions marked "discard" are gone forever.
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org
(tooling-trusted-releases) 01/01: #1067 - add freshness check for npm dependencies
Posted by ar...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
alitheg pushed a commit to branch arm
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
commit 5e8c645962f21d5df469a846568e39e2f2fe4319
Author: Alastair McFarlane <ar...@apache.org>
AuthorDate: Tue Sep 15 15:16:14 2026 +0100
#1067 - add freshness check for npm dependencies
---
.github/dependabot.yml | 8 ++++
.pre-commit-config.yaml | 8 ++++
atr/docs/dependency-updates.md | 24 ++++++++---
bootstrap/context/bump.sh | 6 ++-
bootstrap/source/.npm-exclude-newer | 1 +
scripts/check_npm_dependencies_updated.py | 66 +++++++++++++++++++++++++++++++
6 files changed, 107 insertions(+), 6 deletions(-)
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index f3296f17..371d043c 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -28,6 +28,14 @@ updates:
day: "tuesday"
cooldown:
default-days: 7
+ - package-ecosystem: "npm"
+ directory: "/bootstrap/source"
+ schedule:
+ interval: "weekly"
+ day: "tuesday"
+ # Match bump.sh's 14-day cooldown, so a proposed bump is one bump.sh would also accept
+ cooldown:
+ default-days: 14
# # TODO: Uncomment when pre-commit checks support cooldowns
# - package-ecosystem: "pre-commit"
# directory: "/"
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index aab15711..abef3dbc 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -193,6 +193,14 @@ repos:
pass_filenames: false
always_run: true
+ - id: check-npm-dependencies-updated
+ name: check when npm dependencies were updated
+ description: Verify that npm dependencies were updated within the configured timeframe, for ASVS 15.1.1
+ entry: uv run --frozen python scripts/check_npm_dependencies_updated.py
+ language: system
+ pass_filenames: false
+ always_run: true
+
- id: uv-audit
name: audit dependencies with uv
description: Check uv.lock for known vulnerabilities via OSV, trialled alongside pip-audit
diff --git a/atr/docs/dependency-updates.md b/atr/docs/dependency-updates.md
index 627ad1da..93d03c1f 100644
--- a/atr/docs/dependency-updates.md
+++ b/atr/docs/dependency-updates.md
@@ -19,9 +19,9 @@
ATR depends on three families of third-party code: Python packages, resolved and
locked by uv; the Bootstrap frontend toolkit, installed through npm; and a small
set of command-line tools baked into the container image. We make use of specific
-version pinning. Python dependency freshness is enforced automatically at commit
-time through pre-commit hooks, the Bootstrap toolkit is updated manually by a script,
-and the container tools are verified at image build time.
+version pinning. Python and frontend dependency freshness are both enforced
+automatically at commit time through pre-commit hooks, the Bootstrap toolkit is
+updated by a script, and the container tools are verified at image build time.
This page describes how those dependencies are updated and what guardrails apply.
It covers only ATR's own dependencies. Scanning of the release artifacts that
@@ -32,7 +32,7 @@ users upload is a separate concern and is not covered here.
Python dependencies are pinned in `uv.lock` and resolved by uv. To refresh them,
run `make update-deps`.
-### Freshness
+### Python dependency freshness
The `check-when-dependencies-updated` pre-commit hook runs
[`check_when_dependencies_updated.py`](/ref/scripts/check_when_dependencies_updated.py),
@@ -66,7 +66,20 @@ The script enforces a 14-day cooldown: it installs the requested version with
cannot be pulled in until it has been available for two weeks. It then runs
`npm audit` to check for known vulnerabilities and `npm audit signatures` to
verify the registry signatures, and finally reminds the operator to commit the
-updated `package.json` and `package-lock.json`.
+updated `package.json`, `package-lock.json` and `.npm-exclude-newer`.
+
+### Frontend dependency freshness
+
+The `check-npm-dependencies-updated` pre-commit hook runs
+[`check_npm_dependencies_updated.py`](/ref/scripts/check_npm_dependencies_updated.py),
+which fails if the frontend dependencies are more than 60 days old - a looser
+window than Python's 30 days, since Bootstrap moves more slowly and the 14-day
+cooldown already narrows how new an update can be. `package-lock.json` carries no
+timestamp of its own, so `bump.sh` records its `--before` cutoff in
+`bootstrap/source/.npm-exclude-newer`, and the check reads the age from there. A
+`package-lock.json` edit that skips `bump.sh` does not refresh that file, which
+keeps updates on the `bump.sh` path. On failure it prints
+`Run: bootstrap/context/bump.sh VERSION`.
## External tools in the container image
@@ -91,6 +104,7 @@ There is no automated freshness check for these tools.
## Implementation references
* [`check_when_dependencies_updated.py`](/ref/scripts/check_when_dependencies_updated.py) - the 30-day Python freshness check
+* [`check_npm_dependencies_updated.py`](/ref/scripts/check_npm_dependencies_updated.py) - the 60-day frontend freshness check
* [`bump.sh`](/ref/bootstrap/context/bump.sh) - the Bootstrap update script
* [`Dockerfile.alpine`](/ref/Dockerfile.alpine) - pinned external tools
* [`pip-audit.requirements`](/ref/pip-audit.requirements) - pinned tree audited by pip-audit
diff --git a/bootstrap/context/bump.sh b/bootstrap/context/bump.sh
index 30ef4176..3705bf52 100755
--- a/bootstrap/context/bump.sh
+++ b/bootstrap/context/bump.sh
@@ -43,5 +43,9 @@ npm audit
echo "Verifying registry signatures..."
npm audit signatures
+# Record the cutoff so scripts/check_npm_dependencies_updated.py can flag a stale bump, the way
+# uv.lock's exclude-newer feeds the Python check - package-lock.json carries no timestamp of its own
+printf '%s\n' "$CUTOFF" > .npm-exclude-newer
+
echo "Bootstrap updated to version $VERSION"
-echo "Please commit the updated package.json and package-lock.json"
+echo "Please commit the updated package.json, package-lock.json and .npm-exclude-newer"
diff --git a/bootstrap/source/.npm-exclude-newer b/bootstrap/source/.npm-exclude-newer
new file mode 100644
index 00000000..68937ee2
--- /dev/null
+++ b/bootstrap/source/.npm-exclude-newer
@@ -0,0 +1 @@
+2026-08-07T15:51:17Z
diff --git a/scripts/check_npm_dependencies_updated.py b/scripts/check_npm_dependencies_updated.py
new file mode 100755
index 00000000..45a1366f
--- /dev/null
+++ b/scripts/check_npm_dependencies_updated.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import datetime
+import pathlib
+import sys
+from typing import Final
+
+# Looser than the 30-day Python window: the frontend deps are Bootstrap's CSS/JS, which move more
+# slowly, and bump.sh's 14-day cooldown already narrows the window from publish to allowed
+_MAX_AGE_DAYS: Final[int] = 60
+
+# bump.sh writes its --before cutoff here, the npm counterpart of uv.lock's exclude-newer. It's a
+# committed file rather than the lockfile's mtime, which a fresh checkout would reset to now
+_EXCLUDE_NEWER_PATH: Final[pathlib.Path] = pathlib.Path("bootstrap/source/.npm-exclude-newer")
+
+
+def main() -> None:
+ if not _EXCLUDE_NEWER_PATH.exists():
+ print(f"ERROR: {_EXCLUDE_NEWER_PATH} not found", file=sys.stderr)
+ print("Run: bootstrap/context/bump.sh VERSION", file=sys.stderr)
+ sys.exit(1)
+
+ timestamp = _parse_timestamp(_EXCLUDE_NEWER_PATH.read_text(encoding="utf-8").strip())
+ if timestamp is None:
+ print(f"ERROR: Could not parse a timestamp from {_EXCLUDE_NEWER_PATH}", file=sys.stderr)
+ print("Run: bootstrap/context/bump.sh VERSION", file=sys.stderr)
+ sys.exit(1)
+
+ now = datetime.datetime.now(datetime.UTC)
+ age = now - timestamp
+
+ if age > datetime.timedelta(days=_MAX_AGE_DAYS):
+ print(f"ERROR: npm dependencies are {age.days} days old (the limit is {_MAX_AGE_DAYS} days)", file=sys.stderr)
+ print(f"Last updated: {timestamp.isoformat()}", file=sys.stderr)
+ print("Run: bootstrap/context/bump.sh VERSION", file=sys.stderr)
+ sys.exit(1)
+
+ print(f"OK: npm dependencies are {age.days} days old (the limit is {_MAX_AGE_DAYS} days)")
+
+
+def _parse_timestamp(timestamp_str: str) -> datetime.datetime | None:
+ try:
+ return datetime.datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
+ except ValueError:
+ return None
+
+
+if __name__ == "__main__":
+ main()
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org