Skip to content
Closed
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
14 changes: 14 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ 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.172` adds opt-in first delivery of fields whose actual Schema
declares `readOnCreateOnly: true`. Only `edit-apikey` enables it. A nonenumerable
request-private callback delivers the successful create values once to a
detached clone, not to serialized metadata or canonical cache. Matching Store,
generation, API base, opaque generated ID, concrete type and owner are required;
newer subscribe state and nested-resource adoption are preserved. Other
NewOrEdit hook arguments/results and consumers retain their previous contracts.
The save owner clears its own pending delivery on success and failure; rejected
duplicates cannot clear another save's lock or values. Compatibility revision 6
is a new archive with the same dependency graph. Source/package checks pass;
local Chrome tests have not run because of incomplete shared dependencies.
Official tests, publication and packaged native acceptance are pending, not
full-matrix PASS. See the [release note](docs/releases/web-console-1.6.172.md).

Published `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
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

## Project status

Candidate `1.6.172` preserves API-key create-only first delivery when a redacted
subscribe model arrives before POST/201. Only the API-key editor opts into a
request-private, Schema-bound delivery to its detached clone; newer canonical
state and nested resources remain intact, and the canonical Store does not need
to retain the secret. Compatibility revision 6 replaces revision 5 without
changing dependency versions or the graph. Source/package checks pass; new
installed-Store and save-owner regressions have been added, including personal
and project stores with 100 deterministic barriers each. Local Chrome tests
have not run because the local shared dependency layout is incomplete. Official
tests, publication and packaged native acceptance remain pending. Historical
HOLDs remain HOLD; the full matrix is INCOMPLETE. See the
[release note](docs/releases/web-console-1.6.172.md).

Published `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
Expand Down
3 changes: 2 additions & 1 deletion app/components/edit-apikey/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default ModalBase.extend(NewOrEdit, {
model: null,
clone: null,
justCreated: false,
createOnlyDelivery: true,

didReceiveAttrs() {
this.set('clone', this.get('originalModel').clone());
Expand Down Expand Up @@ -52,7 +53,7 @@ export default ModalBase.extend(NewOrEdit, {
{
this.setProperties({
justCreated: true,
clone: neu.clone()
clone: this.cloneForCreateDelivery(neu)
});
}
},
Expand Down
35 changes: 35 additions & 0 deletions app/mixins/new-or-edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { alias } from '@ember/object/computed';
import { service } from '@ember/service';
import Mixin from '@ember/object/mixin';
import Resource from 'ember-api-store/models/resource';
import { bindCreateOnlyDelivery, cloneCreateOnlyDelivery, takeCreateOnlyDelivery } from 'ember-api-store/utils/create-only-delivery';
import Errors from 'ui/utils/errors';

export default Mixin.create({
Expand All @@ -11,6 +12,7 @@ export default Mixin.create({
errors: null,
saving: false,
editing: true,
createOnlyDelivery: false,
primaryResource: alias('model'),
originalPrimaryResource: alias('originalModel'),

Expand Down Expand Up @@ -106,6 +108,14 @@ export default Mixin.create({
let finalizerError = null;

if ( this._saveOwner === owner ) {
if ( this._createOnlyRequest && this._createOnlyRequest.owner === owner ) {
takeCreateOnlyDelivery(this._createOnlyRequest.options);
this._createOnlyRequest = null;
}
if ( this._createOnlyDelivery && this._createOnlyDelivery.owner === owner ) {
this._createOnlyDelivery.data.fields = null;
this._createOnlyDelivery = null;
}
this._saveOwner = null;
// A hook that turned saving on and then threw still owns that
// state, but a submission which found a pre-existing saving=true
Expand Down Expand Up @@ -199,11 +209,36 @@ export default Mixin.create({
},

doSave: function(opt) {
const owner = this._saveOwner;
if ( owner && this.get('createOnlyDelivery') ) {
opt = opt || {};
Object.defineProperty(this, '_createOnlyRequest', {
value: { owner, options: opt }, writable: true, configurable: true,
});
bindCreateOnlyDelivery(opt, (data) => {
if ( this._saveOwner === owner && !this.isDestroyed && !this.isDestroying ) {
Object.defineProperty(this, '_createOnlyDelivery', {
value: { owner, data }, writable: true, configurable: true,
});
} else {
data.fields = null;
}
});
}
return this.get('primaryResource').save(opt).then((newData) => {
return this.mergeResult(newData);
});
},

cloneForCreateDelivery(resource) {
const pending = this._createOnlyDelivery;
if ( !pending || pending.owner !== this._saveOwner ) {
return resource.clone();
}
this._createOnlyDelivery = null;
return cloneCreateOnlyDelivery(resource, pending.data);
},

mergeResult: function(newData) {
var original = this.get('originalPrimaryResource');
if ( original )
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "@pasturestack/web-console",
"version": "1.6.171",
"version": "1.6.172",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@pasturestack/web-console",
"version": "1.6.171",
"version": "1.6.172",
"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.5.tgz",
"ember-api-store": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.6.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.5.tgz",
"integrity": "sha512-m+IpOrSUqogl3EP8DqefpDuO/9leZ4Bycge7MLwqYASOz75V/J6ay1bFGaOWd2ckaohymODeOlkVzyVzmWLupw==",
"resolved": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.6.tgz",
"integrity": "sha512-ojkclvGZq8iObzwSkOBtZxkt9IwZ0GJvmi8CMYFocBwol6YQh9Q4D6g4t6/o/3mNDYmDkULPgdXBVt81xm5BqA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
Expand Down
1 change: 0 additions & 1 deletion docs/releases/web-console-1.6.171.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ existing 2026-10-10 review boundary. Formal package checks found no affected
build-package modules in the static artifact, without making a runtime
not-affected VEX or zero-vulnerability claim. No dependency or security-policy
change is introduced by this documentation update.

## Upgrade and rollback

Use the separately released Server patch that packages this exact component.
Expand Down
65 changes: 65 additions & 0 deletions docs/releases/web-console-1.6.172.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Web Console 1.6.172

Candidate first-delivery repair. Official tests, publication and packaged QA
are separate pending gates; historical failed receipts remain HOLD.

## Root cause and contract

Revision 5 correctly adopts a newer cached subscribe model instead of importing
an older POST/201 snapshot. For an API key, subscribe can already contain
`secretValue: null`; discarding the whole 201 also loses its only delivery of the
new secret. The API-key editor therefore cannot show its expected detached
first-delivery clone. Requiring canonical Store secrets to survive later
redacted subscribe updates is neither the fix nor the acceptance contract.

Engine 333 source `0d94f7d879d314235e582a7f4062914a27b82709` maps auth-overlay
permission `o` to `FieldImpl.readOnCreateOnly` in `AuthOverlayPostProcessor`.
`Field.isReadOnCreateOnly` and its JavaBean implementation export the actual
Schema resource-field property `readOnCreateOnly`. This repair uses that exact
property; it does not invent a schema flag or merge all create-response fields.

## Minimal change

An ID-less create request captures only Schema-marked field names in its
nonenumerable internal identity metadata. An opt-in request-private Symbol
callback transports only those successful POST/201 values. API-key editing is
the sole NewOrEdit opt-in. Values are withheld from the canonical import and
consumed once into the editor's detached clone, whose visible/copy value remains
independent of later subscribe redaction. Normal cached state and nested models
are not re-imported from the older response.

Delivery requires the same Store, generation, API base, exact generated ID,
concrete type and account binding. The existing save owner clears only its own
pending callback and delivery, including failed hooks and synchronous completion
exceptions. Duplicate submissions neither resend create nor clear the owner's
lock or values. Existing hook arguments/results, non-opted-in consumers, backend
permissions, API payloads and request counts remain unchanged.

API-store compatibility revision 6 is a new archive. Earlier archives and
upstream license text are retained; dependency versions and graph are unchanged.
The source/package checker accepts Windows license line endings while requiring
the unchanged upstream content and exact source/archive equality.

## Verification boundary

The ten prior installed-Store ordering regressions remain. Added cases cover
actual API-key doneSaving delivery, redacted subscribe before 201, later
redaction, personal/project Stores (100 deterministic deferred HTTP barriers
each, without sleeps), uncached one-shot delivery, private metadata, store/
generation/base/type/account mismatch, and synchronous delivery exceptions.
NewOrEdit tests cover delivery cleanup across success, request rejection,
synchronous doneSaving/completion exceptions and rejected duplicate submissions;
ordinary consumers keep their prior options and return value.

Source/package checks pass. The local Chrome suite has not started because the
local junction-based dependency layout is incomplete; it is not reported as a
test PASS. Exact-source official tests, immutable publication and packaged native
first-delivery acceptance remain pending. Historical HOLDs and the complete
permission/resource/locale matrix are not promoted.

## Upgrade and rollback

Use only a separately published Server package containing this exact component.
Retain existing settings, persistent volumes and previous immutable artifacts.
No database migration or backend change is required. This candidate does not
authorize deployment, live retries or a change to authentication settings.
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.171",
"version": "1.6.172",
"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.5.tgz",
"ember-api-store": "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.6.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.171" ]]; then
echo "UNEXPECTED_UI_ARTIFACT_VERSION version=$version expected=1.6.171"
if [[ "$version" != "1.6.172" ]]; then
echo "UNEXPECTED_UI_ARTIFACT_VERSION version=$version expected=1.6.172"
failures=$((failures + 1))
fi

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.171 browser-session broker-broadcast
1.6.172 browser-session broker-broadcast
4 changes: 2 additions & 2 deletions scripts/check-ui-critical-high-dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ for gate in ("node ./scripts/test-ui-npm-audit.js", "node ./scripts/check-ui-npm
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"
api_store_compat_spec = "file:vendor/ember-api-store-compat/ember-api-store-2.8.5-pasturestack.6.tgz"
lock_bytes = lock_path.read_bytes()
baseline_bytes = baseline_path.read_bytes()
if lock_bytes != baseline_bytes:
Expand All @@ -70,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.171":
if package.get("version") != "1.6.172":
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
Loading
Loading