Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,28 @@ Web Console preserves compatible API paths, schema and resource names, action na

Visible branding, product-owned assets, icon identifiers, package metadata, and operator documentation use PastureStack. Historical identifiers remain only where they are server data or protocol contracts and must not be mechanically replaced.

Candidate `1.6.171` confines create-response adoption to ID-less POST/201 and an
existing exact-ID/concrete-type canonical model in the same Store, generation
and API base. It does not re-import stale scalar or nested create fields over
that model. The original draft-save completion identity and subtype/base aliases
remain intact. Resource IDs are not normalized. Missing schemas grant no access.
GET, PUT, action POST (including reused options), uncached creates, non-201,
204 and error paths retain normal processing. No API authorization, session,
MFA, payload, resource lifecycle or backend changes are introduced.
Revision 5 is a new archive; revision 4 is not overwritten. Focused Chrome
validation passed 36/36, including ten new cases and 100 barrier iterations;
failure, skip and todo counts are zero. Official validation, publication and
packaged fresh-volume acceptance remain pending, not full-matrix PASS.
See the [release note](docs/releases/web-console-1.6.171.md).

The live npm audit retains its Critical/High threshold. An explicit dated
vendor-pending record covers only `GHSA-vfj7-8cjw-p6xm` in the exact existing
development-only `[email protected]` dependency closure, for which upstream has no
patched release. Unknown findings, changed affected nodes, runtime exposure,
audit errors and expired reviews fail closed. This is a recorded remaining High
risk, not a patched or zero-High claim; dependencies and package versions are
unchanged. See [the review record](docs/security/npm-vendor-pending.json).

Published `1.6.170` accepts null only for the optional expanded `mounts`
projection while retaining the real complete empty pool relationship and full
scoped mount-cache proof. It preserves nonempty raw ID binding, current-project
Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,29 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

## Project status

Candidate `1.6.171` repairs a shared Store ordering defect: a delayed initial
create response could overwrite a newer subscribe model and leave a successfully
created local Volume stuck in its initial state. Only ID-less create POST/201
uses an existing exact-ID, concrete-type canonical model in the same Store,
generation and API base. Ordinary reads, updates, actions and backend permissions
keep their existing contracts. API-store compatibility revision 5 replaces
revision 4 without changing the dependency graph; earlier archives are retained.
Focused Chrome validation passed 36/36 tests, including ten new regressions and
100 deterministic subscribe-before-201 barrier iterations, with no failures,
skips or todo. Official validation, immutable publication and packaged fresh-volume
acceptance are separate pending gates. The complete permission /
resource / locale matrix remains INCOMPLETE. See the
[release note](docs/releases/web-console-1.6.171.md).

The first exact-source official run stopped before tests on newly reviewed
`GHSA-vfj7-8cjw-p6xm` in build-only `[email protected]`; upstream has no patched
release. It remains a High vendor-pending finding, not a zero-vulnerability
claim. The live audit preserves the High threshold and rejects unexpected
advisories, dependency drift, non-development exposure and expired reviews.
Only the exact reviewed advisory's dependency closure may remain pending until
2026-10-10. No third-party runtime patch or toolchain downgrade is applied.
See the [bounded risk record](docs/security/npm-vendor-pending.json).

Published `1.6.170` corrects an optional `mounts: null` projection being
mistaken for a real allocation in the shared local-volume list. It preserves
the complete advertised pool relationship, full scoped mount cache, exact-volume
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "@pasturestack/web-console",
"version": "1.6.170",
"version": "1.6.171",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@pasturestack/web-console",
"version": "1.6.170",
"version": "1.6.171",
"license": "Apache-2.0",
"dependencies": {
"sass": "1.103.1"
Expand All @@ -33,7 +33,7 @@
"core-js": "file:vendor/core-js-compat/core-js-2.6.13-rc16.0.tgz",
"d3": "7.9.0",
"dagre-d3-es": "7.0.14",
"ember-api-store": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.4.tgz",
"ember-api-store": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.5.tgz",
"ember-auto-import": "2.13.1",
"ember-basic-dropdown": "9.0.0",
"ember-cli": "7.2.0",
Expand Down Expand Up @@ -9051,8 +9051,8 @@
},
"node_modules/ember-api-store": {
"version": "2.8.5",
"resolved": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.4.tgz",
"integrity": "sha512-Z/ZLyAm2ne25B17gONI/s/ufRRz1uH4CfOZ3VbUItBwXnSpW+ckZKub+2vC82fr9YOtgrgIsqirBMf3yfWo2Zw==",
"resolved": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.5.tgz",
"integrity": "sha512-m+IpOrSUqogl3EP8DqefpDuO/9leZ4Bycge7MLwqYASOz75V/J6ay1bFGaOWd2ckaohymODeOlkVzyVzmWLupw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
Expand Down
70 changes: 70 additions & 0 deletions docs/releases/web-console-1.6.171.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Web Console 1.6.171

Candidate shared Store fix; publication and packaged QA remain separate gates.

## Root cause and changes

In packaged native QA, subscribe delivered an inactive created local Volume
before the browser received its original HTTP 201 response. Importing that
initial response replaced the newer canonical model with registering fields.
The backend creation succeeded, but the frontend never reached the expected
stable model state. This is not fixed by relaxing allocation or loading checks.

`vendor/ember-api-store-compat/addon/mixins/type.js` marks only an ID-less new
record's POST with its concrete type, Store generation and API base. Existing
record saves and actions discard a reused marker. The marker is internal request
metadata, not JSON payload. The existing save merge and canonical alias logic
preserve the saved draft's identity.

`vendor/ember-api-store-compat/addon/services/store.js` uses a canonical model
already present for the exact opaque ID and concrete type only for a matching
create POST/201 in that same Store/generation/API base. It does not typeify the
old response's fields or nested resources over that model. HTTP status and xhr
metadata retain their contracts. Uncached create, GET, PUT, action, non-201,
204 and errors retain the existing path. This is not a general timestamp-based
ordering rule for all updates.

Compatibility revision 5 uses a new immutable archive; revision 4 is unchanged.
The lockfile's dependency versions/graph remain unchanged. No authentication,
backend, authorization, data migration or production configuration changes.

## Verification boundary

Ten regression tests use the installed Store/Resource/Schema/Collection package,
not an alternate handwritten store. A deferred HTTP barrier repeats the
subscribe-before-201 race 100 times without sleeps. Adjacent cases cover
uncached creation, subtype/base aliases, stale nested fields, case-sensitive
IDs, distinct stores, reset generation, changed base, ordinary methods,
204/errors, existing-save option reuse and action option reuse.

Focused local Chrome 153 validation passed 36/36 tests with zero failure, skip
or todo, including all ten new cases and 100 deferred-barrier iterations.
Adjacent Store/schema/reference, allocation-proof, route and subscribe-session
cases remain passing. The installed revision-5 archive matches the runtime source.
Exact-source official validation, signed numeric release and packaged native
fresh-volume create/cancel/refresh/denial/removal remain pending.
Historical failed QA receipts stay HOLD; the complete
permission/resource/locale matrix remains INCOMPLETE.

## Upstream-pending build dependency

Official run 37092519936 stopped before QUnit on the newly reviewed
[braces stack-exhaustion advisory](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm).
The registry's latest version remains 3.0.3 and the advisory lists no patched
release. Existing build-tool consumers remain unchanged. Do not apply the npm
suggested forced Ember CLI downgrade or privately patch third-party code.

The [dated risk record](../security/npm-vendor-pending.json) keeps this High
finding visible. The live audit remains fail-closed at High for any other or
changed advisory, changed affected dependency nodes, non-development exposure,
expired review or audit failure. Only this exact reviewed build-only closure
may remain vendor-pending until 2026-10-10. That exception is not a claim that
the vulnerable package is patched or that the source graph has zero High
findings. The packaged static artifact must exclude the affected Node package.

## Upgrade and rollback

Use the separately released Server patch that packages this exact component.
Retain existing Compose environment, persistent volumes and the previous
immutable image. No database migration or runtime patch is required. This work
does not authorize company deployment or a change to HAProxy/OIDC settings.
39 changes: 39 additions & 0 deletions docs/security/npm-vendor-pending.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"schemaVersion": 1,
"advisoryUrl": "https://github.com/advisories/GHSA-vfj7-8cjw-p6xm",
"cve": "CVE-2026-93687",
"severity": "high",
"upstreamPatchedVersion": null,
"reviewedAt": "2026-10-03T03:22:25Z",
"reviewUntil": "2026-10-10",
"scope": "controlled-dev-build-inputs-only",
"risk": "Deeply nested brace patterns can exhaust the build Node.js stack. This High finding remains unresolved; reviewed source filenames/glob configuration are controlled build inputs, not browser/user-supplied patterns.",
"publicationBlockedIfShippedNodes": true,
"shippedNodes": [],
"boundaryEvidence": [
"The exact reverse lock dependency closure below is dev:true and is not reachable from package-lock root production dependencies.",
"The closure enters through ember-cli, a build CLI. The gate checks literal imports in app/config/vendor JavaScript and ember-cli-build.js; only the exact build entry require('ember-cli/lib/broccoli/ember-app') may reach this closure. This static check is not packaged-browser proof.",
"CI builds an immutable checkout with npm ci --ignore-scripts; this decision does not authorize running a build on untrusted patterns or shipping these nodes.",
"This is a source inventory/build-input review, not a zero-CVE statement or runtime not-affected VEX. If a packaged browser/module inventory includes any reviewed node, publication is blocked and this decision must be re-reviewed."
],
"nodes": [
{ "path": "node_modules/braces", "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true },
{ "path": "node_modules/micromatch", "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true },
{ "path": "node_modules/findup-sync", "version": "5.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", "dev": true },
{ "path": "node_modules/find-yarn-workspace-root", "version": "2.0.0", "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", "dev": true },
{ "path": "node_modules/sane", "version": "5.0.1", "resolved": "https://registry.npmjs.org/sane/-/sane-5.0.1.tgz", "integrity": "sha512-9/0CYoRz0MKKf04OMCO3Qk3RQl1PAwWAhPSQSym4ULiLpTZnrY1JoZU0IEikHu8kdk2HvKT/VwQMq/xFZ8kh1Q==", "dev": true },
{ "path": "node_modules/broccoli", "version": "4.0.0", "resolved": "https://registry.npmjs.org/broccoli/-/broccoli-4.0.0.tgz", "integrity": "sha512-p5el5/ig0QeRGFPkLMPdm7KblkTm44eicEWfwnRTz6hncghVuRZ0+XDAtCi7ynxobeE/mey5Q7lAulFkgNzxVA==", "dev": true },
{ "path": "node_modules/ember-cli", "version": "7.2.0", "resolved": "https://registry.npmjs.org/ember-cli/-/ember-cli-7.2.0.tgz", "integrity": "sha512-EafquLJ+EVHz0nNo32NWwAfHr5UxTXn9zdlukuKZFSFrR4G6RRStmBPQ5O0bLSaQVDtU+jOe5gGTHSS4Xy3uQA==", "dev": true }
],
"edges": [
{ "from": "node_modules/micromatch", "to": "node_modules/braces", "spec": "^3.0.3" },
{ "from": "node_modules/findup-sync", "to": "node_modules/micromatch", "spec": "^4.0.4" },
{ "from": "node_modules/find-yarn-workspace-root", "to": "node_modules/micromatch", "spec": "^4.0.2" },
{ "from": "node_modules/sane", "to": "node_modules/micromatch", "spec": "^4.0.2" },
{ "from": "node_modules/broccoli", "to": "node_modules/findup-sync", "spec": "^5.0.0" },
{ "from": "node_modules/broccoli", "to": "node_modules/sane", "spec": "^5.0.1" },
{ "from": "node_modules/ember-cli", "to": "node_modules/broccoli", "spec": "^4.0.0" },
{ "from": "node_modules/ember-cli", "to": "node_modules/find-yarn-workspace-root", "spec": "^2.0.0" },
{ "from": "node_modules/ember-cli", "to": "node_modules/sane", "spec": "^5.0.1" }
]
}
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pasturestack/web-console",
"version": "1.6.170",
"version": "1.6.171",
"private": true,
"description": "PastureStack browser console for the compatible control platform.",
"repository": {
Expand Down Expand Up @@ -76,7 +76,7 @@
"core-js": "file:vendor/core-js-compat/core-js-2.6.13-rc16.0.tgz",
"d3": "7.9.0",
"dagre-d3-es": "7.0.14",
"ember-api-store": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.4.tgz",
"ember-api-store": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.5.tgz",
"ember-auto-import": "2.13.1",
"ember-basic-dropdown": "9.0.0",
"ember-cli": "7.2.0",
Expand Down
4 changes: 2 additions & 2 deletions scripts/check-modernization-blockers
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ with open('package.json', encoding='utf-8') as f:
print(json.load(f).get('version', ''))
PY
)
if [[ "$version" != "1.6.170" ]]; then
echo "UNEXPECTED_UI_ARTIFACT_VERSION version=$version expected=1.6.170"
if [[ "$version" != "1.6.171" ]]; then
echo "UNEXPECTED_UI_ARTIFACT_VERSION version=$version expected=1.6.171"
failures=$((failures + 1))
fi

Expand Down
2 changes: 2 additions & 0 deletions scripts/check-node24-lock-baseline
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ docker run --rm \
cp package.json "$tmpdir/package.json"
cp package-lock.json "$tmpdir/package-lock.json"
cp scripts/node24-lock-smoke.js "$tmpdir/node24-lock-smoke.js"
mkdir -p "$tmpdir/tests/unit/vendor"
cp tests/unit/vendor/api-store-create-order-test.js "$tmpdir/tests/unit/vendor/api-store-create-order-test.js"
mkdir -p "$tmpdir/public/licenses"
cp public/licenses/qrcode-generator-MIT.txt "$tmpdir/public/licenses/qrcode-generator-MIT.txt"
mkdir -p "$tmpdir/vendor"
Expand Down
2 changes: 1 addition & 1 deletion scripts/check-ui-console-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,4 @@ if [[ -n ${PASTURESTACK_PRIVATE_MARKER:-} ]] && grep -RInF -- "$PASTURESTACK_PRI
fi

printf 'UI_CONSOLE_WORKSPACE_OK version=%s persistence=%s cross_tab=%s\n' \
1.6.170 browser-session broker-broadcast
1.6.171 browser-session broker-broadcast
14 changes: 9 additions & 5 deletions scripts/check-ui-critical-high-dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,13 @@ if failures:

package = json.loads(package_path.read_text(encoding="utf-8"))
ci_source = ci_path.read_text(encoding="utf-8")
if "npm audit --audit-level=high" not in ci_source:
fail("live npm Critical/High audit gate is missing from scripts/ci")
api_store_compat_spec = "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.4.tgz"
for gate in ("node ./scripts/test-ui-npm-audit.js", "node ./scripts/check-ui-npm-audit.js"):
if gate not in ci_source:
fail(f"live fail-closed Critical/High audit gate is missing: {gate}")
for evidence in ("scripts/check-ui-npm-audit.js", "scripts/test-ui-npm-audit.js", "docs/security/npm-vendor-pending.json"):
if not Path(evidence).is_file():
fail(f"reviewed live audit evidence is missing: {evidence}")
api_store_compat_spec = "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.5.tgz"
lock_bytes = lock_path.read_bytes()
baseline_bytes = baseline_path.read_bytes()
if lock_bytes != baseline_bytes:
Expand All @@ -66,7 +70,7 @@ if lock_bytes != baseline_bytes:
lock = json.loads(lock_bytes)
packages = lock.get("packages", {})
root = packages.get("", {})
if package.get("version") != "1.6.170":
if package.get("version") != "1.6.171":
fail(f"unexpected Web Console version: {package.get('version')}")
if root.get("version") != package.get("version"):
fail(f"lock root version differs: {root.get('version')}")
Expand Down Expand Up @@ -169,7 +173,7 @@ if failures:

print(
"UI_CRITICAL_HIGH_DEPENDENCIES_OK "
"critical_babel_traverse=absent high_build_chain=patched "
"critical_babel_traverse=absent security_pins=retained "
+ " ".join(f"{name}={count}" for name, count in sorted(checked.items()))
)
print("failure_count=0")
Expand Down
Loading
Loading