diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 53735cf..dc61369 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -3,10 +3,16 @@ name: Nightly on: schedule: - cron: "0 8 * * *" + workflow_dispatch: + jobs: build: # runs-on: macOS-latest runs-on: macos-15 + permissions: + id-token: write + contents: write + attestations: write timeout-minutes: 10 steps: - uses: actions/checkout@v5 @@ -30,22 +36,23 @@ jobs: sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf - name: Build run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive - - name: Create ZIPs + - name: Create ZIP run: | ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip - ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive ./Archive.zip - name: Notarize env: APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip - - name: Attest - id: attest - uses: actions/attest-build-provenance@v2 - with: - subject-path: 'Secretive.zip' - name: Upload App to Artifacts + id: upload uses: actions/upload-artifact@v4 with: name: Secretive.zip path: Secretive.zip + - name: Attest + id: attest + uses: actions/attest-build-provenance@v2 + with: + subject-name: "Secretive.zip" + subject-digest: sha256:${{ steps.upload.outputs.artifact-digest }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ebd0b01..da81788 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,39 +56,34 @@ jobs: sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf - name: Build run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive - - name: Create ZIPs + - name: Create ZIP run: | ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip - ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive ./Xcode_Archive.zip - name: Notarize env: APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip + - name: Upload App to Artifacts + id: upload + uses: actions/upload-artifact@v4 + with: + name: Secretive.zip + path: Secretive.zip - name: Attest id: attest uses: actions/attest-build-provenance@v2 with: - subject-path: 'Secretive.zip, Xcode_Archive.zip' + subject-name: "Secretive.zip" + subject-digest: ${{ steps.upload.outputs.artifact-digest }} - name: Create Release run: | sed -i.tmp "s/RUN_ID/$RUN_ID/g" .github/templates/release.md sed -i.tmp "s/ATTESTATION_ID/$ATTESTATION_ID/g" .github/templates/release.md gh release create $TAG_NAME -d -F .github/templates/release.md gh release upload Secretive.zip - gh release upload Xcode_Archive.zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG_NAME: ${{ github.ref }} RUN_ID: ${{ github.run_id }} ATTESTATION_ID: ${{ steps.attest.outputs.attestation-id }} - - name: Upload App to Artifacts - uses: actions/upload-artifact@v4 - with: - name: Secretive.zip - path: Secretive.zip - - name: Upload Archive to Artifacts - uses: actions/upload-artifact@v4 - with: - name: Xcode_Archive.zip - path: Xcode_Archive.zip diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/CryptoKitMigrator.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/CryptoKitMigrator.swift index ddcc042..a4c69d2 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/CryptoKitMigrator.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/CryptoKitMigrator.swift @@ -30,7 +30,7 @@ extension SecureEnclave { SecItemCopyMatching(privateAttributes, &privateUntyped) guard let privateTyped = privateUntyped as? [[CFString: Any]] else { return } let migratedPublicKeys = Set(store.secrets.map(\.publicKey)) - var migrated = false + var migratedAny = false for key in privateTyped { let name = key[kSecAttrLabel] as? String ?? String(localized: .unnamedSecret) let id = key[kSecAttrApplicationLabel] as! Data @@ -45,20 +45,24 @@ extension SecureEnclave { // Best guess. let auth: AuthenticationRequirement = String(describing: accessControl) .contains("DeviceOwnerAuthentication") ? .presenceRequired : .unknown - let parsed = try CryptoKit.SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: tokenObjectID) - let secret = Secret(id: UUID().uuidString, name: name, publicKey: parsed.publicKey.x963Representation, attributes: Attributes(keyType: .init(algorithm: .ecdsa, size: 256), authentication: auth)) - guard !migratedPublicKeys.contains(parsed.publicKey.x963Representation) else { - logger.log("Skipping \(name), public key already present. Marking as migrated.") + do { + let parsed = try CryptoKit.SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: tokenObjectID) + let secret = Secret(id: UUID().uuidString, name: name, publicKey: parsed.publicKey.x963Representation, attributes: Attributes(keyType: .init(algorithm: .ecdsa, size: 256), authentication: auth)) + guard !migratedPublicKeys.contains(parsed.publicKey.x963Representation) else { + logger.log("Skipping \(name), public key already present. Marking as migrated.") + try markMigrated(secret: secret, oldID: id) + continue + } + logger.log("Migrating \(name).") + try store.saveKey(tokenObjectID, name: name, attributes: secret.attributes) + logger.log("Migrated \(name).") try markMigrated(secret: secret, oldID: id) - continue + migratedAny = true + } catch { + logger.error("Failed to migrate \(name): \(error).") } - logger.log("Migrating \(name).") - try store.saveKey(tokenObjectID, name: name, attributes: secret.attributes) - logger.log("Migrated \(name).") - try markMigrated(secret: secret, oldID: id) - migrated = true } - if migrated { + if migratedAny { store.reloadSecrets() } }