Review on #1446 flagged that the publication gate parsed only the first
__DATA_CONST flags word of an otool -l capture, so a universal library
with a healthy first slice and a broken later slice would still ship.
Replace the inline one-shot awk with scripts/release/extract-data-const-
flags.awk, a state machine that emits one flags word per __DATA_CONST
segment in every slice (segname is only honored directly after cmdsize,
so section entries can never contribute), and fail closed if any entry
lacks SG_READ_ONLY.
Add a regression test driven by real otool captures: broken/healthy
v1.0.62 thin binaries, the vendored universal runtime dylib, and a
universal sample whose last slice is broken — the exact case the old
parser wrongly passed. Also remove MACOSX_DEPLOYMENT_TARGET from the
--exec ambient pass-through so the container always receives the single
unconditional 11.0 pin from compiler_env.
The v1.0.62 darwin/amd64 asset was rejected by dyld before main() with
'__DATA_CONST segment missing SG_READ_ONLY flag' (#1441). The osxcross
x86_64 wrapper in the pinned cross image defaults the deployment target
to macOS 10.13, where ld64-711 emits __DATA_CONST without SG_READ_ONLY;
the arm64 toolchain floor is 11.0 and is unaffected. CGO=0 builds used
Go's internal linker and were also unaffected.
Pin MACOSX_DEPLOYMENT_TARGET=11.0 for the CGO release builds, matching
the arm64 floor and the vendored SafeChat library, and add a release
gate that statically checks SG_READ_ONLY on the binary and its runtime
library and launches every Darwin asset the macOS runner can execute
(amd64 via Rosetta) before publication.
Verified against the pinned cross image: the real dws darwin/amd64
binary builds with __DATA_CONST flags 0x10 (was 0x0), CGO_ENABLED=1 and
the SafeChat backend linked.
Schema runtime cache shared-root installer hardening: validate and lock every parent directory before creation or chmod, and re-verify before the first permission change. Adds symlink-swap regression tests for non-sticky writable parents and sticky-parent acceptance.
The per-target CC/CXX templates resolve through .Env. .goreleaser.yaml also
declares the twelve CC_/CXX_ entries earlier in the same builds.env list, and
GoReleaser happens to surface those to later entries because TemplateEnv
re-binds the template after each evaluation. That is an undocumented internal,
so a GoReleaser upgrade could silently leave every target with an empty CC and
fall back to the host toolchain under CGO_ENABLED=1.
Export the same twelve values from the cross-toolchain wrapper as explicit
--env NAME=VALUE entries, so the container process environment supplies them
regardless of how the config list is evaluated. The config entries stay, which
keeps a direct goreleaser invocation self-contained.
TestReleaseCrossCompilerEnvMatchesWrapper compares the two sources for every
goos/goarch in the release matrix and asserts the wrapper actually forwards
them to docker run, so a value can only be added, changed or dropped in one
place if the other disagrees. Verified non-vacuous by perturbing
CC_darwin_amd64 and observing the mismatch report.
Review follow-ups on the default-CGO SafeChat release change:
- Hold the trackedCipher mutex across the whole backend call so Close
waits for in-flight operations. The vendor client reads Client.inited
before taking its own mutex, so a Close overlapping an encrypt or
decrypt was a reproducible data race now that the backend ships in
every default CGO build.
- Refuse musl-based Linux in install.sh, install-event.sh, and
install-devapp.sh before resolving or downloading the asset. The
release binaries link glibc and cannot start on musl, which previously
surfaced only as an opaque loader error after a successful install.
- Record the breaking removal of dws safechat selftest/decrypt with the
chat crypto decrypt migration path, and document the glibc baseline.
- Stage, verify, and atomically publish the cached GoReleaser and Zig
tools behind a mkdir lock, and re-verify both the pinned archive digest
and the executable digest on a cache hit. An interrupted download or
extraction can no longer leave a half-installed tool that a later run
would accept.
- Pin that every goos/goarch target in the release matrix declares its
CC_/CXX_ entries, so the per-target compiler template cannot silently
resolve to an empty compiler.
The npm registry started answering legacy audit calls with a deprecation
notice ("This endpoint is being retired. Use the bulk advisory endpoint
instead"). On hosted runners the notice rode along the pinned-npm pack
invocation on stderr and the call latency behind it stretched the pack to
312s, failing TestReleaseNpmPackingIgnoresLifecycleScripts — which
asserted on CombinedOutput even though the script's real contract (the
one release.yml consumes via command substitution) is integrity-only
stdout. Disable audit/fund banners for the deterministic pack and assert
stdout separately from stderr diagnostics.
A universal Agent whose obsolete private copy cannot be retired installs
nothing there, yet every entry point counted that retirement failure as an
install failure — aborting `npm install`, `dws skill setup`, and the shell
installers even when the canonical store and all links published correctly,
and skipping the skills-state write. Route retirement failures to a separate
warning path across all surfaces (Go upgrade + skill setup, npm, PowerShell,
install.sh, install-skills.sh, install-event.sh, install-devapp.sh).
Also:
- Add a checked-rename fallback for filesystems that reject the atomic
no-replace flag (NFS, FUSE, overlayfs); the no-clobber contract is kept and
the previously unsupported platforms build and work.
- PowerShell multi-mode links only bundle skills, never the shared canonical
store, so third-party/user skills are no longer fanned into every Agent root.
- Prune ~/.dws/skill-backups to the newest 5 on every surface; encode
HOME-relative backup names on PowerShell to preserve origin.
- Add simulated-win32 junction coverage and rewrite the tautological
no-replace test; remove dead code whose tests gave false coverage.
- Soften the overstated Windows ownership-proof comment (NTFS tunneling).
The fragment gate only ran validation when the changed path matched the
legal fragment name pattern, so `.changes/Foo.md`, `.changes/notes.txt`
and a symlinked fragment slipped through untouched and then broke the
next PR that added a legal fragment. The trigger now fires on any
top-level `.changes/` change other than README.md and rejects every
entry that is not README.md, released/, or a 100644 blob named
^[a-z0-9][a-z0-9._-]*\.md$.
The renderer had the same hole from the other side: `find -type f`
is false for symlinks, so a symlinked fragment was silently dropped
from the rendered notes, and the `[a-z0-9]*.md` glob only constrained
the first character so `chat reply.md` passed. It now walks every
top-level entry and fails on symlinks, unexpected directories,
non-regular files and illegal names. Both scripts pin LC_ALL=C so the
ASCII ranges cannot match uppercase under a different collation.
Adds regression coverage for illegal names, non-markdown entries,
symlinks and executable modes on both the gate and the renderer.
Gitee API returns HTTP 200 with null body when a release tag doesn't
exist, unlike GitHub which returns 404. Treat empty release_id as
"no release exists" instead of erroring out.
Stable releases previously required a byte-identical tree with the
promoted beta (only CHANGELOG.md could differ) and local releases had
to run exactly at the origin/main tip with an atomic main+tag push.
Together these froze main for the whole beta-to-stable window.
Relax both gates while keeping the beta soak mandatory:
- stable still requires an explicit delivered, non-withdrawn beta whose
commit is an ancestor of the sealed release commit; the tree-identity
drift check is removed
- local releases accept any clean sealed commit contained in
origin/main history (any branch or detached HEAD) and push only the
release tag; command-compatibility checks compare the sealed HEAD,
matching CI
ossutil 2.x signs requests with V4 and refuses to run without an
explicit region, so the OSS mirror sync would fail in CI even with
valid credentials. Derive OSS_REGION from the endpoint host
(including -internal variants) and fail fast when it cannot be
derived.