OAS v0.20.1
OAS v0.20.1
OAS v0.20.1 is a corrective release for the v0.20.0 capability-materialization
line. The framework release includes @oas-framework/oas@0.20.1,
@oas-framework/pi@0.20.1, and OAS Desktop 0.20.1. There are no new features;
the changes are the three corrections below and the hardening they forced.
Doctor recognizes revised-v2 capability locks
oas doctor no longer reports installed capabilities from a canonical
revised-v2 lock as orphans. The orphan check is scope-exact: a capability row
is judged against the lock of the scope that installed it, reading the
revised-v2 capabilities table directly instead of inferring provenance from
package rows. Legacy v1 locks keep their previous diagnostic behavior.
Own-property config handling and __proto__ rejection
Config parsing and diagnostics no longer consult inherited Object.prototype
properties anywhere: key dispatch, capability binding, command-owner lookup,
and shape validation are own-property. YAML keys named __proto__ are refused
with the typed failure unsafe-config-key. Internal engine annotations
(underscore keys such as _capabilityLock) are stripped from every manifest
and soul reader, so on-disk files cannot impersonate engine state.
Configless oas use states the real problem
Running oas use in a scope with no config chain now fails with the typed
error E_NO_CONFIG and prints a deterministic remedy — initialize the scope
with oas init --raw --dir <dir> — instead of the misleading acquired: none
report. OAS does not author adopter policy: the remedy initializes an empty
config; adopting a package profile remains an explicit separate step.
Config writes fail closed
Text that would change the shape of a written config is now refused with
typed failures instead of being written:
unsafe-config-value— values containing line breaks (including U+2028,
U+2029, and U+0085, which earlier releases wrote and then silently dropped
on read), embedded" #"(which opens a trailing comment), empty values,
and leading YAML structure indicators.unsafe-config-key— keys and--soul/--typenames carrying:,#,
or__proto__.
This includes the scaffolded name: line: oas init, and the first
oas use/oas type add in a fresh scope, now refuse to run in a directory
whose basename cannot be stored as one YAML scalar — for example a name
beginning with @, #, or a flow bracket, or containing " #" or a line
break. The refusal names the offending basename and writes nothing. This is a
deliberate behavior change: earlier releases wrote such names verbatim, and a
basename containing a line break could inject top-level config blocks.
Untrusted text (directory names, $HOME) is never used as a regex
replacement string, so names containing $&-style sequences are stored and
reported literally.
Desktop parity with the kernel
The OAS Desktop deployment reader now reads revised-v2 capability locks (it
previously rejected them) and matches the kernel's judgments: it refuses
every lock shape the kernel refuses (path canonical form, source grammar,
duplicate dependencies), and its legacy-v1 artifact digest now counts .git
and nested lock files exactly as the kernel does — a payload planted in a
v1-locked artifact after locking is integrity drift in the app, not an
invisible exclusion.
Compatibility
- New typed failures:
E_NO_CONFIG(configlessoas use),
unsafe-config-key,unsafe-config-value. Scripts matching error text
should match the typed codes. oas initand first-write commands refuse directory basenames that cannot
be stored as one YAML scalar (see above).- No lockfile, manifest, or CLI-surface changes otherwise; v0.20.0 locks and
configs are unaffected.
See the package engine contract for
the typed-failure table.