@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.
Files changed (36) hide show
  1. package/THIRD-PARTY-NOTICES.md +51 -0
  2. package/deploy/macos/build-macos-pkg.sh +35 -5
  3. package/deploy/macos/scripts/setup-litertlm.sh +35 -10
  4. package/deploy/windows/README.md +17 -4
  5. package/deploy/windows/build-windows.ps1 +25 -2
  6. package/deploy/windows/ci/list-shipped-scripts.ps1 +58 -0
  7. package/deploy/windows/ci/tb-canary.ps1 +18 -0
  8. package/deploy/windows/ci/tb-canary.vbs +17 -0
  9. package/deploy/windows/ci/verify-allsigned-enforcement.ps1 +608 -0
  10. package/deploy/windows/e2e/test-headless-principal.ps1 +632 -0
  11. package/deploy/windows/ensure-sensing.ps1 +91 -1
  12. package/deploy/windows/register-litertlm-task.ps1 +114 -15
  13. package/deploy/windows/register-task.ps1 +162 -12
  14. package/deploy/windows/setup-litertlm.ps1 +78 -32
  15. package/deploy/windows/stop-existing.ps1 +2 -2
  16. package/deploy/windows/trillboards-hidden-run.vbs +3 -3
  17. package/deploy/windows/trillboards-setup.ps1 +2 -2
  18. package/dist/CloudSensingManager.d.ts +13 -4
  19. package/dist/CloudSensingManager.d.ts.map +1 -1
  20. package/dist/CloudSensingManager.js +6 -0
  21. package/dist/CloudSensingManager.js.map +1 -1
  22. package/dist/EdgeAgent.js +1 -1
  23. package/dist/LiteRtVlmProvider.d.ts +108 -45
  24. package/dist/LiteRtVlmProvider.d.ts.map +1 -1
  25. package/dist/LiteRtVlmProvider.js +124 -84
  26. package/dist/LiteRtVlmProvider.js.map +1 -1
  27. package/dist/diagnose.d.ts +1 -1
  28. package/dist/diagnose.js +1 -1
  29. package/dist/localSenseE2eHarness.d.ts +17 -4
  30. package/dist/localSenseE2eHarness.d.ts.map +1 -1
  31. package/dist/localSenseE2eHarness.js +11 -1
  32. package/dist/localSenseE2eHarness.js.map +1 -1
  33. package/dist/sensingRunMode.d.ts.map +1 -1
  34. package/dist/sensingRunMode.js +49 -31
  35. package/dist/sensingRunMode.js.map +1 -1
  36. package/package.json +1 -1
@@ -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) that installs + runs on
41
- # every Mac. This is the RELEASE artifact: a browser can't reliably detect a
42
- # Mac's CPU arch (Safari reports "MacIntel" even on Apple Silicon), so the portal
43
- # cannot hand out an arch-specific download. --arch builds a single-arch .pkg
44
- # (faster, for local testing).
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, but actively repair a
174
- # broken one. Older connector versions could let uv bind the tool to Apple's
175
- # Python 3.9; current LiteRT-LM uses Python features introduced in 3.10 and then
176
- # crash-loops before serving. --force rebuilds that existing tool environment
177
- # with the explicit managed interpreter while --upgrade refreshes the package.
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
- if [ -x "$LITERTLM" ] && "$LITERTLM" list >/dev/null 2>&1; then
181
- log "litert-lm CLI is healthy — keeping current install"
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
- log "installing/repairing litert-lm with uv-managed Python $LITERT_PYTHON"
184
- if ! "$UV" tool install --python "$LITERT_PYTHON" --managed-python --upgrade --force litert-lm >>"$LOG" 2>&1; then
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
@@ -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 logon Scheduled Task
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 logon tasks, then opens **Trillboards CCTV Setup** without a
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 and restarts on every
49
- logon; cloud inference is off by default.
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 = "https://github.com/eugeneware/ffmpeg-static/releases/download/$FfmpegStaticTag/ffmpeg-win32-x64"
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