Skip to content

Commit 70c59fd

Browse files
authored
ci: retire unsupported licensed fork builds (#14)
Retire organization-credentialed integration jobs whose activation contexts cannot be attested by the approved central return action. Preserve exact cleanup fixture coverage and fail-closed aggregates.
1 parent 1c6c4e8 commit 70c59fd

4 files changed

Lines changed: 141 additions & 1445 deletions

File tree

.github/workflows/build-tests-mac.yml

Lines changed: 6 additions & 296 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,6 @@ name: Builds - macOS
22

33
on:
44
workflow_dispatch:
5-
inputs:
6-
mode:
7-
description: 'Run the cleanup contract, one organization smoke, or the upstream full matrix.'
8-
required: true
9-
default: contract-only
10-
type: choice
11-
options:
12-
- contract-only
13-
- smoke
14-
- upstream-full
155

166
concurrency:
177
group: ${{ github.workflow }}-${{ github.ref }}
@@ -25,303 +15,23 @@ jobs:
2515
name: macOS resource cleanup proof contract
2616
runs-on: macos-14
2717
steps:
28-
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
18+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
2919
- name: Exercise private return evidence fixtures
3020
run: bash scripts/test-macos-resource-proof.sh
3121

32-
boundedOrganizationMacOSCanary:
33-
name: StandaloneOSX on 2022.3.62f3 (bounded organization canary)
34-
if: github.repository == 'Ambiguous-Interactive/unity-builder' && inputs.mode == 'smoke'
35-
needs: [resource-cleanup-proof-contract]
36-
runs-on: macos-14
37-
# Explicit step budgets total 144 minutes; keep a 21-minute job-level
38-
# reserve so verification and post cleanup survive a near-budget build.
39-
timeout-minutes: 165
40-
steps:
41-
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
42-
timeout-minutes: 5
43-
with:
44-
lfs: true
45-
46-
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830
47-
timeout-minutes: 5
48-
with:
49-
path: test-project/Library
50-
key: Library-test-project-macos-StandaloneOSX-2022.3.62f3
51-
restore-keys: |
52-
Library-test-project-macos-StandaloneOSX-
53-
Library-test-project-macos-
54-
Library-test-project-
55-
56-
- name: Set scripting backend to IL2CPP
57-
timeout-minutes: 1
58-
run: >-
59-
mv -f ./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset
60-
./test-project/ProjectSettings/ProjectSettings.asset
61-
62-
- name: Require isolated return-process support
63-
id: return-isolation
64-
timeout-minutes: 1
65-
run: python3 -c 'import os; assert hasattr(os, "setsid")'
66-
67-
- name: Acquire organization Unity lock
68-
id: acquire-build-lock
69-
timeout-minutes: 45
70-
uses: Ambiguous-Interactive/ambiguous-organization-build-lock/.github/actions/acquire-build-lock-with-cleanup@59a2fa98224569e5a697f271a3ac4b866c53ac2c # v1.8.3
71-
with:
72-
lock-name: wallstop-organization-builds
73-
lock-repository: Ambiguous-Interactive/ambiguous-organization-build-lock
74-
runner-id: ${{ runner.name }}
75-
holder-id-suffix: ${{ github.job }}
76-
timeout-minutes: '40'
77-
require-resource-lifecycle: 'true'
78-
minimum-release-cooldown-seconds: '1'
79-
env:
80-
BUILD_LOCK_APP_ID: ${{ secrets.BUILD_LOCK_APP_ID }}
81-
BUILD_LOCK_APP_PRIVATE_KEY: ${{ secrets.BUILD_LOCK_APP_PRIVATE_KEY }}
82-
83-
- name: Build bounded macOS smoke
84-
id: build
85-
if: ${{ steps.acquire-build-lock.outputs.acquired == 'true' }}
86-
continue-on-error: true
87-
timeout-minutes: 70
88-
uses: ./
89-
env:
90-
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
91-
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
92-
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
93-
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
94-
with:
95-
allowDirtyBuild: true
96-
buildName: 'GameCI Test Build'
97-
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
98-
projectPath: test-project
99-
targetPlatform: StandaloneOSX
100-
unityVersion: 2022.3.62f3
101-
102-
- name: Return macOS Unity license on the same runner
103-
id: return-license
104-
if: ${{ always() && steps.acquire-build-lock.outputs.acquired == 'true' && steps.build.outputs.resourceCleanupStatus != 'confirmed' }}
105-
continue-on-error: true
106-
timeout-minutes: 5
107-
env:
108-
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
109-
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
110-
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
111-
run: |
112-
set -euo pipefail
113-
attempt="$(mktemp -d "${RUNNER_TEMP}/unity-builder-fallback-return.XXXXXX")"
114-
trap 'rm -rf -- "${attempt}"' EXIT
115-
mkdir -p "${attempt}/project"
116-
export ACTION_FOLDER="${GITHUB_WORKSPACE}/dist"
117-
export ACTIVATE_LICENSE_PATH="${attempt}/project"
118-
export UNITY_VERSION=2022.3.62f3
119-
export UNITY_LICENSING_SERVER=''
120-
export UNITY_BUILDER_RESOURCE_RETURN_LOG_PATH="${attempt}/return.log"
121-
export UNITY_BUILDER_RESOURCE_STATUS_PATH="${attempt}/return.status"
122-
export UNITY_BUILDER_RETURN_TIMEOUT_SECONDS=180
123-
export UNITY_BUILDER_RETURN_KILL_GRACE_SECONDS=10
124-
fallback_nonce="$(uuidgen | tr '[:upper:]' '[:lower:]')"
125-
export UNITY_BUILDER_RESOURCE_PROOF_NONCE="${fallback_nonce}"
126-
export UNITY_BUILDER_RESOURCE_PROOF_PATH="${attempt}/proof"
127-
source dist/platforms/mac/steps/return_license.sh
128-
129-
status="$(cat "${attempt}/return.status" 2>/dev/null || true)"
130-
cleanup_status=unknown
131-
resource_health=healthy
132-
resource_reason=return-missing-positive-evidence
133-
if awk 'BEGIN { found=0 } { line=tolower($0); if (line ~ /20111/ && line ~ /(licen[cs]|activation|entitlement)/ && line ~ /(error|fail|limit|maximum|blocked|return|code)/) found=1 } END { exit !found }' "${attempt}/return.log"; then
134-
resource_health=blocked
135-
resource_reason=unity-account-limit-20111
136-
elif [[ "${status}" == completed:0 ]] &&
137-
[[ "$(cat "${attempt}/proof" 2>/dev/null || true)" == "resource-safe=${fallback_nonce}" ]] &&
138-
grep -Eq '^(\[Licensing::Module\] )?Successfully returned the entitlement license$' "${attempt}/return.log" &&
139-
grep -Eq '^(Serial number unavailable for ULF return|\[Licensing::Client\] Successfully returned ULF license with serial number[[:space:]]*:[[:space:]]*[^[:space:]]+)$' "${attempt}/return.log"; then
140-
cleanup_status=confirmed
141-
resource_reason=cleanup-confirmed
142-
elif [[ "${status}" == timeout ]]; then
143-
resource_reason=return-timeout
144-
elif [[ "${status}" == terminated ]]; then
145-
resource_reason=return-terminated
146-
fi
147-
evidence_digest="$(printf '%s' "${fallback_nonce}:${status}:${cleanup_status}:${resource_health}:${resource_reason}" | shasum -a 256 | awk '{print $1}')"
148-
{
149-
echo "cleanup-status=${cleanup_status}"
150-
echo "resource-health=${resource_health}"
151-
echo "resource-reason=${resource_reason}"
152-
echo "evidence-digest=${evidence_digest}"
153-
} >>"${GITHUB_OUTPUT}"
154-
155-
- name: Release organization Unity lock
156-
id: release-build-lock
157-
if: ${{ always() }}
158-
timeout-minutes: 5
159-
uses: Ambiguous-Interactive/ambiguous-organization-build-lock/.github/actions/release-build-lock@59a2fa98224569e5a697f271a3ac4b866c53ac2c # v1.8.3
160-
with:
161-
lock-name: wallstop-organization-builds
162-
lock-repository: Ambiguous-Interactive/ambiguous-organization-build-lock
163-
runner-id: ${{ runner.name }}
164-
holder-id-suffix: ${{ github.job }}
165-
holder-id: ${{ steps.acquire-build-lock.outputs.holder-id }}
166-
resource-cleanup-status: ${{ steps.return-license.outputs.cleanup-status || steps.build.outputs.resourceCleanupStatus || 'unknown' }}
167-
resource-health: ${{ (steps.acquire-build-lock.outputs.resource-health == 'blocked' || steps.build.outputs.resourceHealth == 'blocked' || steps.return-license.outputs.resource-health == 'blocked') && 'blocked' || 'healthy' }}
168-
resource-reason: ${{ (steps.acquire-build-lock.outputs.resource-health == 'blocked' || steps.build.outputs.resourceHealth == 'blocked' || steps.return-license.outputs.resource-health == 'blocked') && 'unity-account-limit-20111' || steps.return-license.outputs.resource-reason || steps.build.outputs.resourceReason || steps.acquire-build-lock.outputs.resource-reason || 'cleanup-evidence-unknown' }}
169-
env:
170-
BUILD_LOCK_APP_ID: ${{ secrets.BUILD_LOCK_APP_ID }}
171-
BUILD_LOCK_APP_PRIVATE_KEY: ${{ secrets.BUILD_LOCK_APP_PRIVATE_KEY }}
172-
173-
- name: Require a successful build and exact cleanup evidence
174-
id: verify-cleanup
175-
if: ${{ always() }}
176-
timeout-minutes: 2
177-
env:
178-
ACQUIRED: ${{ steps.acquire-build-lock.outputs.acquired }}
179-
BUILD_OUTCOME: ${{ steps.build.outcome }}
180-
CLEANUP_STATUS: ${{ steps.return-license.outputs.cleanup-status || steps.build.outputs.resourceCleanupStatus }}
181-
EVIDENCE_DIGEST: ${{ steps.return-license.outputs.evidence-digest || steps.build.outputs.resourceEvidenceDigest }}
182-
ACQUIRE_HOLDER_ID: ${{ steps.acquire-build-lock.outputs.holder-id }}
183-
RELEASE_AVAILABLE_AT: ${{ steps.release-build-lock.outputs.available-at }}
184-
RELEASE_CLEANUP_RESULT: ${{ steps.release-build-lock.outputs.cleanup-result }}
185-
RELEASE_HOLDER_ID: ${{ steps.release-build-lock.outputs.holder-id }}
186-
RELEASE_OUTCOME: ${{ steps.release-build-lock.outcome }}
187-
RELEASED: ${{ steps.release-build-lock.outputs.released }}
188-
RELEASE_RESERVATION_STATE: ${{ steps.release-build-lock.outputs.reservation-state }}
189-
RESOURCE_HEALTH: ${{ (steps.acquire-build-lock.outputs.resource-health == 'blocked' || steps.build.outputs.resourceHealth == 'blocked' || steps.return-license.outputs.resource-health == 'blocked') && 'blocked' || 'healthy' }}
190-
RESOURCE_REASON: ${{ (steps.acquire-build-lock.outputs.resource-health == 'blocked' || steps.build.outputs.resourceHealth == 'blocked' || steps.return-license.outputs.resource-health == 'blocked') && 'unity-account-limit-20111' || steps.return-license.outputs.resource-reason || steps.build.outputs.resourceReason || steps.acquire-build-lock.outputs.resource-reason }}
191-
run: |
192-
set -euo pipefail
193-
if [[ "${RESOURCE_HEALTH}" == blocked || "${RESOURCE_REASON}" == unity-account-limit-20111 ]]; then
194-
echo '::error::Unity reported the account-limit 20111 incident.'
195-
exit 1
196-
fi
197-
if [[ "${ACQUIRED}" != true || "${BUILD_OUTCOME}" != success ]]; then
198-
echo '::error::Bounded macOS build did not succeed after lock admission.'
199-
exit 1
200-
fi
201-
if [[ "${CLEANUP_STATUS}" != confirmed || "${RESOURCE_HEALTH}" != healthy || "${RESOURCE_REASON}" != cleanup-confirmed ]]; then
202-
echo '::error::macOS cleanup did not produce the exact confirmed/healthy/cleanup-confirmed tuple.'
203-
exit 1
204-
fi
205-
if [[ "${RELEASE_OUTCOME}" != success ]]; then
206-
echo "::error::Schema-5 lock release finished with ${RELEASE_OUTCOME}."
207-
exit 1
208-
fi
209-
if [[ "${RELEASED}" != true || "${RELEASE_CLEANUP_RESULT}" != cooldown-started || "${RELEASE_RESERVATION_STATE}" != cooldown ]]; then
210-
echo '::error::Release did not remove the holder into the required cooldown.'
211-
exit 1
212-
fi
213-
if [[ -z "${ACQUIRE_HOLDER_ID}" || "${RELEASE_HOLDER_ID}" != "${ACQUIRE_HOLDER_ID}" || -z "${RELEASE_AVAILABLE_AT}" ]]; then
214-
echo '::error::Release outputs do not prove exact holder removal and cooldown availability.'
215-
exit 1
216-
fi
217-
if [[ ! "${EVIDENCE_DIGEST}" =~ ^[0-9a-f]{64}$ ]]; then
218-
echo '::error::macOS cleanup evidence digest is missing or malformed.'
219-
exit 1
220-
fi
221-
echo "::notice::macOS cleanup evidence reason=${RESOURCE_REASON} evidence-digest=${EVIDENCE_DIGEST}"
222-
223-
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
224-
if: ${{ success() }}
225-
timeout-minutes: 5
226-
with:
227-
name: Build StandaloneOSX on macOS (2022.3.62f3)
228-
path: build
229-
retention-days: 14
230-
231-
buildForAllPlatformsMacOS:
232-
name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
233-
if: ${{ github.repository == 'game-ci/unity-builder' && inputs.mode == 'upstream-full' }}
234-
needs: [resource-cleanup-proof-contract]
235-
runs-on: macos-latest
236-
strategy:
237-
fail-fast: false
238-
max-parallel: 1
239-
matrix:
240-
projectPath:
241-
- test-project
242-
unityVersion:
243-
- 2021.3.45f2
244-
- 2022.3.62f3
245-
- 2023.2.22f1
246-
targetPlatform:
247-
- StandaloneOSX
248-
- iOS
249-
include:
250-
- unityVersion: 6000.0.36f1
251-
targetPlatform: StandaloneOSX
252-
- unityVersion: 6000.0.36f1
253-
targetPlatform: StandaloneOSX
254-
buildProfile: 'Assets/Settings/Build Profiles/Sample macOS Build Profile.asset'
255-
steps:
256-
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
257-
with:
258-
lfs: true
259-
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830
260-
with:
261-
path: ${{ matrix.projectPath }}/Library
262-
key: Library-${{ matrix.projectPath }}-macos-${{ matrix.targetPlatform }}
263-
restore-keys: |
264-
Library-${{ matrix.projectPath }}-macos-
265-
Library-
266-
- name: Set scripting backend to IL2CPP
267-
run: >-
268-
mv -f ./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset
269-
./test-project/ProjectSettings/ProjectSettings.asset
270-
- uses: ./
271-
env:
272-
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
273-
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
274-
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
275-
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
276-
with:
277-
allowDirtyBuild: true
278-
buildName: 'GameCI Test Build'
279-
buildProfile: ${{ matrix.buildProfile }}
280-
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
281-
projectPath: ${{ matrix.projectPath }}
282-
targetPlatform: ${{ matrix.targetPlatform }}
283-
unityVersion: ${{ matrix.unityVersion }}
284-
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
285-
with:
286-
name: Build ${{ matrix.targetPlatform }} on macOS (${{ matrix.unityVersion }})${{ matrix.buildProfile && ' With Build Profile' || '' }}
287-
path: build
288-
retention-days: 14
289-
290-
macos-license-ci:
291-
name: macOS cleanup contract and licensed coverage
22+
macos-cleanup-contract:
23+
name: macOS cleanup contract
29224
if: ${{ always() }}
293-
needs:
294-
- resource-cleanup-proof-contract
295-
- boundedOrganizationMacOSCanary
296-
- buildForAllPlatformsMacOS
25+
needs: [resource-cleanup-proof-contract]
29726
runs-on: ubuntu-latest
29827
steps:
299-
- name: Require the exact requested coverage
28+
- name: Require cleanup fixture coverage
30029
env:
301-
CANARY_RESULT: ${{ needs.boundedOrganizationMacOSCanary.result }}
30230
CONTRACT_RESULT: ${{ needs.resource-cleanup-proof-contract.result }}
303-
MODE: ${{ inputs.mode }}
304-
REPOSITORY: ${{ github.repository }}
305-
UPSTREAM_RESULT: ${{ needs.buildForAllPlatformsMacOS.result }}
30631
run: |
30732
set -euo pipefail
30833
if [[ "${CONTRACT_RESULT}" != success ]]; then
30934
echo "::error::macOS cleanup fixtures finished with ${CONTRACT_RESULT}."
31035
exit 1
31136
fi
312-
case "${REPOSITORY}:${MODE}" in
313-
Ambiguous-Interactive/unity-builder:contract-only|game-ci/unity-builder:contract-only)
314-
[[ "${CANARY_RESULT}" == skipped && "${UPSTREAM_RESULT}" == skipped ]]
315-
echo 'No licensed macOS coverage was requested; cleanup contract fixtures passed.'
316-
;;
317-
Ambiguous-Interactive/unity-builder:smoke)
318-
[[ "${CANARY_RESULT}" == success && "${UPSTREAM_RESULT}" == skipped ]]
319-
;;
320-
game-ci/unity-builder:upstream-full)
321-
[[ "${CANARY_RESULT}" == skipped && "${UPSTREAM_RESULT}" == success ]]
322-
;;
323-
*)
324-
echo "::error::Repository ${REPOSITORY} is not enrolled for licensed macOS coverage."
325-
exit 1
326-
;;
327-
esac
37+
echo 'The fork runs cleanup fixtures without organization Unity credentials.'

0 commit comments

Comments
 (0)