param([string]$DockerContext = "docker-prod") $ErrorActionPreference = "Stop" $continuityContainer = "assistant-continuity-runtime-1" $coreContainer = "assistant-core-runtime-1" $continuityURL = "http://localhost:8081" $coreURL = "http://localhost:8080" function Post-Json([string]$url, [object]$body) { $json = $body | ConvertTo-Json -Depth 8 -Compress $local = New-TemporaryFile $remote = "/tmp/domovoy-$([guid]::NewGuid().ToString('N')).json" try { [IO.File]::WriteAllText($local, $json, [Text.UTF8Encoding]::new($false)) docker --context $DockerContext cp $local "${continuityContainer}:$remote" | Out-Null docker --context $DockerContext exec $continuityContainer wget -qO- --header "Content-Type: application/json" --post-file $remote $url if ($LASTEXITCODE -ne 0) { throw "POST $url failed" } } finally { docker --context $DockerContext exec --user root $continuityContainer rm -f $remote 2>$null Remove-Item -LiteralPath $local -Force } } function Expect-GetStatus([string]$url, [int]$status, [string]$token = "") { $previous = $ErrorActionPreference try { $ErrorActionPreference = "Continue" $response = (docker --context $DockerContext exec --env "CREATOR_TEST_SESSION=$token" $continuityContainer sh -c 'wget -S -O /dev/null --header="Authorization: Bearer $CREATOR_TEST_SESSION" "$0"' $url 2>&1) -join "`n" } finally { $ErrorActionPreference = $previous } if ($response -notmatch "HTTP/1\.[01] $status") { throw "GET $url did not return $status" } } $environment = docker --context $DockerContext inspect --format '{{range .Config.Env}}{{println .}}{{end}}' $coreContainer $bootstrapEntry = $environment | Where-Object { $_ -like "CREATOR_BOOTSTRAP_TOKEN=*" } | Select-Object -First 1 if (-not $bootstrapEntry) { throw "Creator bootstrap token is not configured" } $bootstrapToken = $bootstrapEntry.Substring("CREATOR_BOOTSTRAP_TOKEN=".Length) $sessionResponse = docker --context $DockerContext exec --env "CREATOR_TEST_BOOTSTRAP=$bootstrapToken" $coreContainer sh -c 'wget -qO- --header="Authorization: Bearer $CREATOR_TEST_BOOTSTRAP" --post-data="" "$0/v1/creator/sessions"' $coreURL if ($LASTEXITCODE -ne 0) { throw "Creator session issuance failed" } $creatorSession = ($sessionResponse | ConvertFrom-Json).Token $suffix = [guid]::NewGuid().ToString("N") $ownedID = "creator-prospective-$suffix" $foreignID = "foreign-prospective-$suffix" $common = @{ CommitmentID = "commitment-$suffix"; ScopeID = "domovoy-global-scope"; GoalID = "goal-$suffix" TriggerAtUnixMillis = 1800000000000; State = "ARMED"; Revision = 1 } Post-Json "$continuityURL/v1/prospective-items" ($common + @{ID=$ownedID;OwnerPrincipalID="domovoy-creator-principal"}) Post-Json "$continuityURL/v1/prospective-items" ($common + @{ID=$foreignID;OwnerPrincipalID="another-principal"}) Expect-GetStatus "$continuityURL/v1/creator/prospective-items/$ownedID" 401 $owned = docker --context $DockerContext exec --env "CREATOR_TEST_SESSION=$creatorSession" $continuityContainer sh -c 'wget -qO- --header="Authorization: Bearer $CREATOR_TEST_SESSION" "$0"' "$continuityURL/v1/creator/prospective-items/$ownedID" if ($LASTEXITCODE -ne 0 -or ($owned | ConvertFrom-Json).ID -ne $ownedID) { throw "owned ProspectiveItem was not returned" } Expect-GetStatus "$continuityURL/v1/creator/prospective-items/$foreignID" 403 $creatorSession $listedResponse = docker --context $DockerContext exec --env "CREATOR_TEST_SESSION=$creatorSession" $continuityContainer sh -c 'wget -qO- --header="Authorization: Bearer $CREATOR_TEST_SESSION" "$0"' "$continuityURL/v1/creator/prospective-items?limit=100" if ($LASTEXITCODE -ne 0) { throw "Creator ProspectiveItem list failed" } $listed = $listedResponse | ConvertFrom-Json if (-not ($listed.Items | Where-Object ID -eq $ownedID)) { throw "owned ProspectiveItem missing from list" } if ($listed.Items | Where-Object ID -eq $foreignID) { throw "foreign ProspectiveItem leaked into list" } if ($listed.Items.Count -gt 100) { throw "ProspectiveItem list exceeded hard limit" } Expect-GetStatus "$continuityURL/v1/creator/prospective-items?limit=101" 400 $creatorSession Write-Output "DEV-000028 Creator-owned Continuity list: PASS"