# macOS 인증 빌드 AppSok의 최종 배포 후보는 Flutter 검증, macOS release build, Developer ID signing, Apple notarization, stapling, Gatekeeper assessment를 모두 통과한 ZIP으로 본다. ## 최초 설정 remote Mac runner의 AppSok checkout에서 한 번 실행한다. credential을 교체할 때도 같은 명령을 다시 실행한다. ```bash ./scripts/setup-appsok-ci-secrets.sh ``` 입력하는 값은 Mac login/keychain password, Apple ID email, Apple app-specific password, notary profile 이름이다. 기본 notary profile 이름은 `appsok-notary`다. 설정 스크립트는 다음 항목을 준비한다. - `.sops.yaml`: AppSok CI secret 파일을 암호화할 age recipient rule - `secrets/appsok.ci.sops.json`: SOPS로 암호화된 CI 입력값 - `$HOME/.config/sops/age/appsok-ci-key.txt`: runner local age private key - macOS login Keychain의 notarytool credential profile raw password, app-specific password, decrypted SOPS payload, private key 원문은 tracked file, task log, 최종 응답에 남기지 않는다. ## 인증 빌드 설정이 끝난 뒤 반복 빌드는 아래 한 줄로 실행한다. ```bash ./scripts/build-certified-macos.sh ``` 스크립트는 아래 순서로 실행된다. 1. SOPS secret 복호화와 login Keychain unlock 2. `flutter pub get` 3. `flutter analyze` 4. `flutter test` 5. `flutter build macos` 6. bundled `Contents/Resources/adb-runtime/adb` Developer ID signing 7. `AppSok.app` Developer ID signing 8. `notarytool submit --wait` 9. `stapler staple` 10. `spctl --assess` 11. `AppSok-certified.zip` 생성과 `.sha256` checksum 파일 출력 최종 산출물은 `build/macos/Build/Products/Release/AppSok-certified.zip`이다. Jenkins archived artifact 대상은 이 ZIP과 같은 경로의 `AppSok-certified.zip.sha256` 파일이다. ## 검증 기준 - `flutter analyze`가 `No issues found!`로 끝난다. - `flutter test`가 모두 통과한다. - `notarytool submit --wait` 결과가 `Accepted`다. - `stapler`가 ticket을 붙인다. - `spctl --assess --type execute --verbose=4`가 Notarized Developer ID source를 보고한다. - 최종 ZIP의 `shasum -a 256` 값이 `AppSok-certified.zip.sha256`에 기록된다. 2026-06-14 검증에서는 `AppSok-certified.zip` 생성, notarization accepted, stapling, Gatekeeper assessment를 통과했다. 기록된 checksum은 `1c8e89816d4cbf92bcf7c70aa40a4e36ae29efeaeb3cc64ce391c22bc6deef2a`다. ## 주의 사항 Apple notarization은 앱 번들 안의 executable resource도 별도로 검사한다. `Contents/Resources/adb-runtime/adb`가 Developer ID, hardened runtime, timestamp로 먼저 서명되지 않으면 앱 본체 서명이 정상이어도 notarization이 `Invalid` 처리될 수 있다. `scripts/build-certified-macos.sh`는 이 순서를 고정한다. ## 문제 해결 - `error loading config: no matching creation rules found`: `./scripts/setup-appsok-ci-secrets.sh`를 다시 실행해 `.sops.yaml`과 encrypted secret 파일을 재생성한다. - `HTTP status code: 401. Invalid credentials`: Apple ID, Team ID, app-specific password, notary profile 입력을 확인한다. Apple 계정 로그인 password가 아니라 app-specific password가 필요하다. - `errSecInternalComponent` 또는 `User interaction is not allowed`: login Keychain unlock과 private key partition list 설정이 필요한 상태다. setup script를 interactive terminal에서 다시 실행한다. - notarization log가 bundled `adb`를 지목한다: 인증 빌드 스크립트를 우회하지 말고 `./scripts/build-certified-macos.sh`로 다시 빌드한다.