@trillboards/edge-sdk 0.2.16 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +51 -0
- package/deploy/macos/build-macos-pkg.sh +35 -5
- package/deploy/macos/scripts/setup-litertlm.sh +35 -10
- package/deploy/windows/README.md +17 -4
- package/deploy/windows/build-windows.ps1 +25 -2
- package/deploy/windows/ci/list-shipped-scripts.ps1 +58 -0
- package/deploy/windows/ci/tb-canary.ps1 +18 -0
- package/deploy/windows/ci/tb-canary.vbs +17 -0
- package/deploy/windows/ci/verify-allsigned-enforcement.ps1 +608 -0
- package/deploy/windows/e2e/test-headless-principal.ps1 +632 -0
- package/deploy/windows/ensure-sensing.ps1 +91 -1
- package/deploy/windows/register-litertlm-task.ps1 +114 -15
- package/deploy/windows/register-task.ps1 +162 -12
- package/deploy/windows/setup-litertlm.ps1 +78 -32
- package/deploy/windows/stop-existing.ps1 +2 -2
- package/deploy/windows/trillboards-hidden-run.vbs +3 -3
- package/deploy/windows/trillboards-setup.ps1 +2 -2
- package/dist/CloudSensingManager.d.ts +13 -4
- package/dist/CloudSensingManager.d.ts.map +1 -1
- package/dist/CloudSensingManager.js +6 -0
- package/dist/CloudSensingManager.js.map +1 -1
- package/dist/EdgeAgent.js +1 -1
- package/dist/LiteRtVlmProvider.d.ts +108 -45
- package/dist/LiteRtVlmProvider.d.ts.map +1 -1
- package/dist/LiteRtVlmProvider.js +124 -84
- package/dist/LiteRtVlmProvider.js.map +1 -1
- package/dist/diagnose.d.ts +1 -1
- package/dist/diagnose.js +1 -1
- package/dist/localSenseE2eHarness.d.ts +17 -4
- package/dist/localSenseE2eHarness.d.ts.map +1 -1
- package/dist/localSenseE2eHarness.js +11 -1
- package/dist/localSenseE2eHarness.js.map +1 -1
- package/dist/sensingRunMode.d.ts.map +1 -1
- package/dist/sensingRunMode.js +49 -31
- package/dist/sensingRunMode.js.map +1 -1
- package/package.json +1 -1
package/THIRD-PARTY-NOTICES.md
CHANGED
|
@@ -47,3 +47,54 @@ SOFTWARE.
|
|
|
47
47
|
Frigate™ is a trademark of Frigate, Inc. Its use here is nominative — to
|
|
48
48
|
identify the upstream project this code was ported from. Trillboards is not
|
|
49
49
|
affiliated with, endorsed by, or sponsored by Frigate, Inc.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## FFmpeg
|
|
54
|
+
|
|
55
|
+
The Windows and macOS connector installers bundle a prebuilt static
|
|
56
|
+
`ffmpeg` binary. RTSP capture goes through it — `RTSPCameraProvider` spawns it
|
|
57
|
+
per frame — so it is redistributed as part of the product, not merely used at
|
|
58
|
+
build time.
|
|
59
|
+
|
|
60
|
+
**Which binary.** The Windows x64 build pinned at
|
|
61
|
+
`deploy/windows/build-windows.ps1` is
|
|
62
|
+
`eugeneware/ffmpeg-static` release `b6.0`, asset `ffmpeg-win32-x64`, SHA-256
|
|
63
|
+
`e9fd5e711debab9d680955fc1e38a2c1160fd280b144476cc3f62bc43ef49db1`. That
|
|
64
|
+
project republishes upstream Windows x64 builds from
|
|
65
|
+
[gyan.dev](https://www.gyan.dev/ffmpeg/builds/).
|
|
66
|
+
|
|
67
|
+
**License: GPL v3.** Confirmed two independent ways rather than assumed. The
|
|
68
|
+
upstream builder states "All builds are 64-bit, static and licensed as GPLv3",
|
|
69
|
+
and the binary reports its own configuration as
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
--enable-gpl --enable-version3 --enable-static ... --enable-libx264
|
|
73
|
+
--enable-libx265 --enable-libxvid --enable-libvidstab --enable-librubberband
|
|
74
|
+
--enable-libvmaf --enable-libopencore-amrnb --enable-libopencore-amrwb
|
|
75
|
+
--enable-libvo-amrwbenc ...
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`--enable-gpl` plus `--enable-version3` makes the combined work GPL v3.
|
|
79
|
+
`--enable-nonfree` is **absent**, so the build is redistributable; a `nonfree`
|
|
80
|
+
build would not be, and swapping the pin for one would make shipping it
|
|
81
|
+
unlawful. Check that flag before ever changing the pin.
|
|
82
|
+
|
|
83
|
+
**Corresponding Source (GPL v3 §6).** Trillboards conveys this object code and
|
|
84
|
+
will provide the complete Corresponding Source for the exact binary above, on
|
|
85
|
+
any medium customarily used for software interchange, to anyone who asks at
|
|
86
|
+
**legal@trillboards.com**, for as long as we offer spare parts or customer
|
|
87
|
+
support for this product. The upstream sources are FFmpeg
|
|
88
|
+
(<https://ffmpeg.org/download.html>, <https://git.ffmpeg.org/ffmpeg.git>) and
|
|
89
|
+
the build recipe published by the builder above.
|
|
90
|
+
|
|
91
|
+
**Our modification, stated plainly (GPL v3 §5(a)).** Trillboards redistributes
|
|
92
|
+
this binary unmodified except for one thing: we Authenticode-sign it with our
|
|
93
|
+
own code-signing certificate (publisher `Aethercorp Inc`) before bundling it.
|
|
94
|
+
Upstream ships it unsigned, which makes it an EDR and antivirus false-positive
|
|
95
|
+
magnet and the one unsigned executable in an otherwise fully signed bundle. The
|
|
96
|
+
signature is appended to the PE certificate table; no byte of the program image
|
|
97
|
+
is altered, its version and configuration strings are untouched, and it imposes
|
|
98
|
+
no restriction on anyone — a recipient remains free to strip the signature,
|
|
99
|
+
replace the binary, or rebuild it from the Corresponding Source above. Nothing
|
|
100
|
+
in the product requires `bin\ffmpeg.exe` to be signed in order to run.
|
|
@@ -37,11 +37,41 @@
|
|
|
37
37
|
# air-gapped CI)
|
|
38
38
|
#
|
|
39
39
|
# --universal builds ONE fat arm64+x86_64 .pkg (node + ffmpeg lipo'd from both
|
|
40
|
-
# arches; bundled fsevents.node is already universal)
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
40
|
+
# arches; bundled fsevents.node is already universal). --arch builds a
|
|
41
|
+
# single-arch .pkg.
|
|
42
|
+
#
|
|
43
|
+
# THE RELEASE ARTIFACT IS `--arch arm64`, NOT `--universal`. This comment used to
|
|
44
|
+
# say the opposite — that universal "installs + runs on every Mac" and "is the
|
|
45
|
+
# RELEASE artifact" — and that sentence is why PR #12228 tried to switch the
|
|
46
|
+
# release lane to it. Do not repeat that. A universal .pkg makes `node` and
|
|
47
|
+
# `ffmpeg` fat, and changes nothing about the constraint that actually decides
|
|
48
|
+
# this: `litert_lm_api` is published ONLY for `macosx_12_0_arm64`. There is no
|
|
49
|
+
# macOS x86_64 build to lipo against, and the installed `liblitert-lm.dylib` is
|
|
50
|
+
# arm64-thin. scripts/setup-litertlm.sh:151,156 already encodes that —
|
|
51
|
+
#
|
|
52
|
+
# if [ "$HOST_OS" = "Darwin" ] && [ "$HOST_ARCH" != "arm64" ]; then
|
|
53
|
+
# [ "$REQUIRE_BUNDLED_MODEL" = "1" ] && fail "local AI requires Apple silicon"
|
|
54
|
+
#
|
|
55
|
+
# — and postinstall sets TRILLBOARDS_REQUIRE_BUNDLED_MODEL=1, so on an Intel Mac
|
|
56
|
+
# that refusal is an abort, not a downgrade.
|
|
57
|
+
#
|
|
58
|
+
# The arm64-thin binaries in the shipped .pkg are therefore a SYMPTOM OF THE
|
|
59
|
+
# CORRECT BUILD, not a defect. What the two options actually do on an Intel Mac:
|
|
60
|
+
#
|
|
61
|
+
# --arch arm64 (today) : Installer.app refuses up front. Nothing is written.
|
|
62
|
+
# --universal : the installer ACCEPTS, lays down 2.27 GB, then dies in
|
|
63
|
+
# postinstall — and there is no uninstaller to clean up.
|
|
64
|
+
#
|
|
65
|
+
# Failing before the download beats failing after it. Ship universal only when
|
|
66
|
+
# upstream ships an x86_64 litert-lm AND the arch gate above is relaxed in the
|
|
67
|
+
# same change; the `macos-release-arch-lockstep` guard below fails the build if
|
|
68
|
+
# those two ever disagree.
|
|
69
|
+
#
|
|
70
|
+
# The one true thing the old comment said, kept because it still binds: a browser
|
|
71
|
+
# cannot reliably detect a Mac's CPU arch (Safari reports "MacIntel" even on
|
|
72
|
+
# Apple Silicon), so the portal cannot hand out an arch-specific download. That
|
|
73
|
+
# is an argument for ONE artifact at one URL — it is not an argument that the
|
|
74
|
+
# artifact can run everywhere, and conflating those is the error above.
|
|
45
75
|
#
|
|
46
76
|
# ffmpeg: a pinned static darwin build (eugeneware/ffmpeg-static b6.0 — the same
|
|
47
77
|
# upstream the ffmpeg-static npm package ships) is downloaded at build time and
|
|
@@ -32,6 +32,17 @@ HF_REPO="litert-community/gemma-4-E2B-it-litert-lm"
|
|
|
32
32
|
SERVE_LABEL="com.trillboards.litertlm"
|
|
33
33
|
SERVE_PORT="9379"
|
|
34
34
|
LITERT_PYTHON="${LITERT_LM_PYTHON:-3.12}"
|
|
35
|
+
# PINNED litert-lm. This is not hygiene — the accelerator is selected by posting
|
|
36
|
+
# a `<model-id>,gpu` model id, upstream calls that syntax deprecated, and it has
|
|
37
|
+
# already changed twice without any release of ours: 0.14.0 (2026-07-08) dropped
|
|
38
|
+
# both the `,gpu` entry from `GET /v1/models` AND the parse (measured: 404), and
|
|
39
|
+
# 0.15.0 restored the parse but never the entry. An unpinned `--upgrade` means a
|
|
40
|
+
# customer's per-frame cost can change 1.7-6.6x on a reinstall we did not ship.
|
|
41
|
+
# Keep in lockstep with deploy/windows/setup-litertlm.ps1, LiteRtVlmProvider's
|
|
42
|
+
# LITERT_LM_PINNED_VERSION, and .github/contracts/litert-lm-tested-versions.json
|
|
43
|
+
# — the `litert-lm-version-pin` guard fails CI if they diverge or if this version
|
|
44
|
+
# has no measured entry in that contract.
|
|
45
|
+
LITERT_LM_VERSION="${LITERT_LM_VERSION:-0.16.0}"
|
|
35
46
|
REQUIRE_BUNDLED_MODEL="${TRILLBOARDS_REQUIRE_BUNDLED_MODEL:-0}"
|
|
36
47
|
ALLOW_MODEL_DOWNLOAD="${TRILLBOARDS_ALLOW_MODEL_DOWNLOAD:-0}"
|
|
37
48
|
# Customer packages stage the model here. A network fallback remains available
|
|
@@ -170,18 +181,32 @@ if ! command -v "$UV" >/dev/null 2>&1 && [ ! -x "$UV" ]; then
|
|
|
170
181
|
log "ERROR: uv unavailable; cannot provision LiteRT-LM"; exit 0
|
|
171
182
|
fi
|
|
172
183
|
|
|
173
|
-
# 2. litert-lm CLI. Keep a healthy existing install
|
|
174
|
-
# broken one. Older connector versions could let uv
|
|
175
|
-
# Python 3.9; current LiteRT-LM uses Python features
|
|
176
|
-
# crash-loops before serving. --force rebuilds that
|
|
177
|
-
# with the explicit managed interpreter
|
|
184
|
+
# 2. litert-lm CLI. Keep a healthy existing install AT THE PINNED VERSION, but
|
|
185
|
+
# actively repair a broken or drifted one. Older connector versions could let uv
|
|
186
|
+
# bind the tool to Apple's Python 3.9; current LiteRT-LM uses Python features
|
|
187
|
+
# introduced in 3.10 and then crash-loops before serving. --force rebuilds that
|
|
188
|
+
# existing tool environment with the explicit managed interpreter.
|
|
189
|
+
#
|
|
190
|
+
# The version check is part of "healthy". A `list`-only health check kept every
|
|
191
|
+
# machine on whatever it happened to install first — which is how the box this
|
|
192
|
+
# was designed on stayed on 0.13.1 (where the `,gpu` entry is advertised) while
|
|
193
|
+
# every customer install after 2026-07-08 got a build that omits it. The bug
|
|
194
|
+
# reproduced on their hosts and on none of ours.
|
|
178
195
|
LITERTLM="$LOCAL_BIN/litert-lm"
|
|
179
196
|
[ -x "$LITERTLM" ] || LITERTLM="$(command -v litert-lm || echo "$LITERTLM")"
|
|
180
|
-
|
|
181
|
-
|
|
197
|
+
INSTALLED_LITERT_VERSION=""
|
|
198
|
+
if [ -x "$LITERTLM" ]; then
|
|
199
|
+
INSTALLED_LITERT_VERSION="$("$LITERTLM" --version 2>/dev/null | tr -d '\r' | awk '{print $NF}')"
|
|
200
|
+
fi
|
|
201
|
+
if [ -x "$LITERTLM" ] && [ "$INSTALLED_LITERT_VERSION" = "$LITERT_LM_VERSION" ] \
|
|
202
|
+
&& "$LITERTLM" list >/dev/null 2>&1; then
|
|
203
|
+
log "litert-lm CLI is healthy at pinned $LITERT_LM_VERSION — keeping current install"
|
|
182
204
|
else
|
|
183
|
-
|
|
184
|
-
|
|
205
|
+
if [ -n "$INSTALLED_LITERT_VERSION" ] && [ "$INSTALLED_LITERT_VERSION" != "$LITERT_LM_VERSION" ]; then
|
|
206
|
+
log "litert-lm $INSTALLED_LITERT_VERSION differs from pinned $LITERT_LM_VERSION — reinstalling"
|
|
207
|
+
fi
|
|
208
|
+
log "installing/repairing litert-lm==$LITERT_LM_VERSION with uv-managed Python $LITERT_PYTHON"
|
|
209
|
+
if ! "$UV" tool install --python "$LITERT_PYTHON" --managed-python --force "litert-lm==$LITERT_LM_VERSION" >>"$LOG" 2>&1; then
|
|
185
210
|
[ "$REQUIRE_BUNDLED_MODEL" = "1" ] && fail "litert-lm install/repair failed"
|
|
186
211
|
log "ERROR: litert-lm install/repair failed; local AI will retry later"
|
|
187
212
|
exit 0
|
|
@@ -193,7 +218,7 @@ else
|
|
|
193
218
|
log "ERROR: litert-lm remains unhealthy after repair; local AI will retry later"
|
|
194
219
|
exit 0
|
|
195
220
|
fi
|
|
196
|
-
log "litert-lm CLI repaired successfully"
|
|
221
|
+
log "litert-lm CLI repaired successfully at $("$LITERTLM" --version 2>/dev/null | awk '{print $NF}')"
|
|
197
222
|
fi
|
|
198
223
|
|
|
199
224
|
# 3. Model - import the verified bundled file. Idempotent: skip entirely if
|
package/deploy/windows/README.md
CHANGED
|
@@ -19,7 +19,11 @@ bin\trillboards-pair.cmd hidden setup engine used by the setup window
|
|
|
19
19
|
bin\trillboards-hidden-run.vbs runs a helper with NO console (never use cmd's
|
|
20
20
|
`start`: it allocates a visible console before the
|
|
21
21
|
child can hide itself)
|
|
22
|
-
bin\register-task.ps1 registers the
|
|
22
|
+
bin\register-task.ps1 registers the background Scheduled Task. Tries
|
|
23
|
+
S4U + boot trigger first (runs with NOBODY logged
|
|
24
|
+
on), and steps down one capability at a time to a
|
|
25
|
+
repeating trigger and then an interactive
|
|
26
|
+
principal, so a machine is never left with no task
|
|
23
27
|
bin\stop-existing.ps1 DISABLES the task, stops this install's processes,
|
|
24
28
|
and proves bin\node.exe is unlocked before a swap
|
|
25
29
|
bin\ensure-sensing.ps1 re-arms the task (register/enable/start) — closing
|
|
@@ -40,13 +44,22 @@ serves every Windows 10/11 — no per-arch builds.
|
|
|
40
44
|
2. Run it. Production installers are Authenticode-signed with Azure Trusted
|
|
41
45
|
Signing and the release workflow verifies the signature before publishing.
|
|
42
46
|
3. Installer copies the connector, installs and verifies the included local AI,
|
|
43
|
-
registers the
|
|
47
|
+
registers the startup tasks, then opens **Trillboards CCTV Setup** without a
|
|
44
48
|
command window.
|
|
45
49
|
4. Select **Start setup**. The app opens the Trillboards camera wizard, discovers
|
|
46
50
|
local recorders, and validates each channel. Black, disconnected, and
|
|
47
51
|
unreadable inputs are ignored; only working camera feeds become screens.
|
|
48
|
-
5. Sensing starts with the already-installed local AI
|
|
49
|
-
|
|
52
|
+
5. Sensing starts with the already-installed local AI; cloud inference is off
|
|
53
|
+
by default.
|
|
54
|
+
6. Closing the setup window asks for **one UAC elevation**. That single prompt is
|
|
55
|
+
what makes sensing survive an unattended reboot, and it is a Windows rule
|
|
56
|
+
rather than a preference: an S4U principal performs a batch logon, and Task
|
|
57
|
+
Scheduler grants `SeBatchLogonRight` only when the caller is an administrator
|
|
58
|
+
(boot triggers are Administrators-only for the same reason). Accepting it
|
|
59
|
+
registers both tasks S4U + at boot, so the connector comes back within ~30 s
|
|
60
|
+
of every restart with nobody signed in. Declining it — or installing under a
|
|
61
|
+
standard user, who is never prompted because they could not satisfy it — keeps
|
|
62
|
+
a working task that repeats every 5 minutes but still needs someone logged on.
|
|
50
63
|
|
|
51
64
|
## Build (CI: `release-connector-windows.yml`, runs on `windows-latest`)
|
|
52
65
|
|
|
@@ -35,6 +35,15 @@
|
|
|
35
35
|
.PARAMETER NodeVersion Pinned Node runtime (default v22.22.0, matches macOS).
|
|
36
36
|
.PARAMETER Offline Skip downloads; copy the host node/ffmpeg (air-gapped CI).
|
|
37
37
|
.PARAMETER SkipNsis Stage only; do not compile the NSIS .exe (for unit checks).
|
|
38
|
+
.PARAMETER FfmpegPath Stage THIS ffmpeg.exe instead of downloading one. The
|
|
39
|
+
release workflow fetches the pinned build, verifies its
|
|
40
|
+
SHA-256, Authenticode-signs it, and passes the signed
|
|
41
|
+
copy here — signing changes the bytes, so the hash gate
|
|
42
|
+
has to run before it, not after.
|
|
43
|
+
.PARAMETER PrintFfmpegPin
|
|
44
|
+
Print "<download-url> <sha256>" and exit. The release
|
|
45
|
+
workflow reads the pin from here rather than restating
|
|
46
|
+
it, so the two can never drift.
|
|
38
47
|
|
|
39
48
|
.OUTPUTS
|
|
40
49
|
Prints the inner installer path on the last line:
|
|
@@ -44,7 +53,9 @@
|
|
|
44
53
|
param(
|
|
45
54
|
[string]$NodeVersion = "v22.22.0",
|
|
46
55
|
[switch]$Offline,
|
|
47
|
-
[switch]$SkipNsis
|
|
56
|
+
[switch]$SkipNsis,
|
|
57
|
+
[string]$FfmpegPath = "",
|
|
58
|
+
[switch]$PrintFfmpegPin
|
|
48
59
|
)
|
|
49
60
|
|
|
50
61
|
$ErrorActionPreference = "Stop"
|
|
@@ -55,6 +66,9 @@ Set-StrictMode -Version Latest
|
|
|
55
66
|
# verified after download; refuse to bundle an unverified binary.
|
|
56
67
|
$FfmpegStaticTag = if ($env:FFMPEG_STATIC_TAG) { $env:FFMPEG_STATIC_TAG } else { "b6.0" }
|
|
57
68
|
$FfmpegSha256Win = if ($env:FFMPEG_SHA256_WIN) { $env:FFMPEG_SHA256_WIN } else { "e9fd5e711debab9d680955fc1e38a2c1160fd280b144476cc3f62bc43ef49db1" }
|
|
69
|
+
$FfmpegUrl = "https://github.com/eugeneware/ffmpeg-static/releases/download/$FfmpegStaticTag/ffmpeg-win32-x64"
|
|
70
|
+
|
|
71
|
+
if ($PrintFfmpegPin) { Write-Output "$FfmpegUrl $FfmpegSha256Win"; exit 0 }
|
|
58
72
|
|
|
59
73
|
# ─── Locate ourselves + the edge-sdk package root ─────────────────────────────
|
|
60
74
|
$Here = Split-Path -Parent $MyInvocation.MyCommand.Path # deploy\windows
|
|
@@ -152,8 +166,17 @@ if ($Offline) {
|
|
|
152
166
|
$hostFf = (Get-Command ffmpeg -ErrorAction SilentlyContinue).Source
|
|
153
167
|
if (-not $hostFf) { Die "offline mode: no host ffmpeg on PATH to copy." }
|
|
154
168
|
Copy-Item -Force $hostFf $FfmpegBin
|
|
169
|
+
} elseif ($FfmpegPath) {
|
|
170
|
+
# Supplied by the release workflow AFTER it verified the pinned SHA-256 and
|
|
171
|
+
# Authenticode-signed the binary. Re-checking the hash here would fail by
|
|
172
|
+
# construction: the signature is appended to the PE certificate table, so the
|
|
173
|
+
# signed file cannot hash to the unsigned pin. The pin still gates the build —
|
|
174
|
+
# just one step earlier, in the caller, against the bytes it downloaded.
|
|
175
|
+
if (-not (Test-Path -LiteralPath $FfmpegPath)) { Die "-FfmpegPath does not exist: $FfmpegPath" }
|
|
176
|
+
Log "Staging supplied ffmpeg: $FfmpegPath"
|
|
177
|
+
Copy-Item -Force -LiteralPath $FfmpegPath -Destination $FfmpegBin
|
|
155
178
|
} else {
|
|
156
|
-
$url =
|
|
179
|
+
$url = $FfmpegUrl
|
|
157
180
|
Log "Downloading pinned static ffmpeg: $url"
|
|
158
181
|
Invoke-WebRequest -Uri $url -OutFile "$Scratch\ffmpeg.exe" -UseBasicParsing
|
|
159
182
|
$actual = (Get-FileHash -Algorithm SHA256 "$Scratch\ffmpeg.exe").Hash.ToLower()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Emit the scripts that actually ship inside the connector installer, DERIVED
|
|
4
|
+
from build-windows.ps1 rather than restated.
|
|
5
|
+
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
"What ships" is decided by the `Copy-Item -Force "$Here\<file>"
|
|
8
|
+
"$Payload\bin\..."` calls in build-windows.ps1 - nothing else. A hand-kept
|
|
9
|
+
list beside it is a list that goes stale the first time someone adds a script
|
|
10
|
+
and forgets, and the failure is silent: the new file ships unsigned and only a
|
|
11
|
+
customer under GPO AllSigned finds out.
|
|
12
|
+
|
|
13
|
+
Consumers: the release workflow (which files to Authenticode-sign) and the
|
|
14
|
+
AllSigned enforcement harness (which files to prove).
|
|
15
|
+
|
|
16
|
+
Note deploy/windows/install-service.ps1 is deliberately absent: it is the
|
|
17
|
+
legacy service path, is not copied into the payload, and does not ship.
|
|
18
|
+
|
|
19
|
+
.PARAMETER Kind
|
|
20
|
+
ps1 | vbs | cmd | signable (ps1 + vbs) | all
|
|
21
|
+
|
|
22
|
+
.PARAMETER AbsolutePath
|
|
23
|
+
Emit full paths into deploy/windows instead of bare file names.
|
|
24
|
+
#>
|
|
25
|
+
[CmdletBinding()]
|
|
26
|
+
param(
|
|
27
|
+
[ValidateSet('ps1', 'vbs', 'cmd', 'signable', 'all')][string]$Kind = 'all',
|
|
28
|
+
[switch]$AbsolutePath
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
$ErrorActionPreference = 'Stop'
|
|
32
|
+
Set-StrictMode -Version Latest
|
|
33
|
+
|
|
34
|
+
$windowsDir = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
|
|
35
|
+
$build = Join-Path $windowsDir 'build-windows.ps1'
|
|
36
|
+
if (-not (Test-Path -LiteralPath $build)) { throw "build-windows.ps1 not found next to $PSScriptRoot" }
|
|
37
|
+
|
|
38
|
+
$text = [IO.File]::ReadAllText($build)
|
|
39
|
+
$matched = [regex]::Matches($text, 'Copy-Item\s+-Force\s+"\$Here\\([^"\\]+)"\s+"\$Payload\\bin\\')
|
|
40
|
+
$names = @($matched | ForEach-Object { $_.Groups[1].Value } | Select-Object -Unique)
|
|
41
|
+
|
|
42
|
+
# Derivation floor. If the Copy-Item shape in build-windows.ps1 ever changes,
|
|
43
|
+
# this fails loudly here instead of silently signing nothing downstream.
|
|
44
|
+
if ($names.Count -lt 12) {
|
|
45
|
+
throw "only $($names.Count) staged script(s) derived from build-windows.ps1 - the Copy-Item pattern changed; fix this derivation before trusting any signing step"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
$selected = switch ($Kind) {
|
|
49
|
+
'ps1' { $names | Where-Object { $_ -like '*.ps1' } }
|
|
50
|
+
'vbs' { $names | Where-Object { $_ -like '*.vbs' } }
|
|
51
|
+
'cmd' { $names | Where-Object { $_ -like '*.cmd' } }
|
|
52
|
+
'signable' { $names | Where-Object { $_ -like '*.ps1' -or $_ -like '*.vbs' } }
|
|
53
|
+
default { $names }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
foreach ($n in ($selected | Sort-Object)) {
|
|
57
|
+
if ($AbsolutePath) { Write-Output (Join-Path $windowsDir $n) } else { Write-Output $n }
|
|
58
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# tb-canary.ps1 - CI only. Never staged into the installer payload.
|
|
2
|
+
#
|
|
3
|
+
# The AllSigned enforcement proof needs something it can actually RUN and watch
|
|
4
|
+
# be blocked or admitted. The shipped scripts stop scheduled tasks and move
|
|
5
|
+
# install trees, so they are proved through PowerShell's policy gate without
|
|
6
|
+
# being executed; this stands in for them at execution time, and the release
|
|
7
|
+
# workflow signs it in the SAME Trusted Signing call as the shipped scripts so
|
|
8
|
+
# it carries identical signature provenance.
|
|
9
|
+
#
|
|
10
|
+
# Keep it ASCII and keep it trivial: anything it does other than write a marker
|
|
11
|
+
# would make a 'blocked' result ambiguous.
|
|
12
|
+
# [CmdletBinding()] on purpose: it lets the harness validate its non-executing
|
|
13
|
+
# policy probe against this same file, because an unknown named parameter then
|
|
14
|
+
# fails to bind instead of falling through to $args and running the body.
|
|
15
|
+
[CmdletBinding()]
|
|
16
|
+
param([string]$MarkerPath = "")
|
|
17
|
+
if ($MarkerPath) { [IO.File]::WriteAllText($MarkerPath, "ran") }
|
|
18
|
+
exit 0
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Option Explicit
|
|
2
|
+
|
|
3
|
+
' tb-canary.vbs - CI only. Never staged into the installer payload.
|
|
4
|
+
'
|
|
5
|
+
' The .vbs half of the AllSigned enforcement proof. WSH has its own gate
|
|
6
|
+
' (TrustPolicy=2, "run only signed and trusted scripts"), which PowerShell's
|
|
7
|
+
' execution policy does not cover, so the .vbs enforcement is measured
|
|
8
|
+
' separately. Signed in the same Trusted Signing call as the shipped scripts.
|
|
9
|
+
|
|
10
|
+
Dim fso, args, f
|
|
11
|
+
Set args = WScript.Arguments
|
|
12
|
+
If args.Count > 0 Then
|
|
13
|
+
Set fso = CreateObject("Scripting.FileSystemObject")
|
|
14
|
+
Set f = fso.CreateTextFile(args(0), True)
|
|
15
|
+
f.WriteLine "ran"
|
|
16
|
+
f.Close
|
|
17
|
+
End If
|