Compare commits

..

7 Commits

Author SHA1 Message Date
Max Goedjen
c8cf0db1c5 Remove some unused stirngs. (#664) 2025-09-04 05:03:48 +00:00
Max Goedjen
412687467b Digest wants 'sha256:' prefix that the upload step doesn't add for some reason (#667) 2025-09-04 05:01:44 +00:00
Max Goedjen
416a7d5f40 Fix attestation issue from double-zip file process in upload action (#666)
* Remove archives since we don’t strip symbols anyway.

* Attest upload result.
2025-09-03 21:38:22 -07:00
Max Goedjen
c4605fb60e Update nightly.yml (#665) 2025-09-03 08:49:20 +00:00
Max Goedjen
61eed5987c Add permissions to nightly (#663)
* Add permissions to nightly

* Add archives
2025-09-03 08:39:59 +00:00
Max Goedjen
cbef7c6181 Add manual trigger to nightly (#662) 2025-09-03 08:25:00 +00:00
Max Goedjen
63a09390b8 Temporarily disable previews (#661)
* Previews

* Temporarily disable.
2025-09-03 08:11:55 +00:00
11 changed files with 80 additions and 131 deletions

View File

@@ -3,10 +3,16 @@ name: Nightly
on: on:
schedule: schedule:
- cron: "0 8 * * *" - cron: "0 8 * * *"
workflow_dispatch:
jobs: jobs:
build: build:
# runs-on: macOS-latest # runs-on: macOS-latest
runs-on: macos-15 runs-on: macos-15
permissions:
id-token: write
contents: write
attestations: write
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- uses: actions/checkout@v5 - 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 sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf
- name: Build - name: Build
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
- name: Create ZIPs - name: Create ZIP
run: | run: |
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive ./Archive.zip
- name: Notarize - name: Notarize
env: env:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} 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 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 - name: Upload App to Artifacts
id: upload
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: Secretive.zip name: Secretive.zip
path: 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 }}

View File

@@ -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 sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf
- name: Build - name: Build
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
- name: Create ZIPs - name: Create ZIP
run: | run: |
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip 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 - name: Notarize
env: env:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} 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 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 - name: Attest
id: attest id: attest
uses: actions/attest-build-provenance@v2 uses: actions/attest-build-provenance@v2
with: with:
subject-path: 'Secretive.zip, Xcode_Archive.zip' subject-name: "Secretive.zip"
subject-digest: ${{ steps.upload.outputs.artifact-digest }}
- name: Create Release - name: Create Release
run: | run: |
sed -i.tmp "s/RUN_ID/$RUN_ID/g" .github/templates/release.md 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 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 create $TAG_NAME -d -F .github/templates/release.md
gh release upload Secretive.zip gh release upload Secretive.zip
gh release upload Xcode_Archive.zip
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ github.ref }} TAG_NAME: ${{ github.ref }}
RUN_ID: ${{ github.run_id }} RUN_ID: ${{ github.run_id }}
ATTESTATION_ID: ${{ steps.attest.outputs.attestation-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

View File

@@ -3403,28 +3403,6 @@
} }
} }
}, },
"integrations_public_key_path_placeholder" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "YOUR_PUBLIC_KEY_PATH"
}
}
}
},
"integrations_public_key_placeholder" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "YOUR_PUBLIC_KEY"
}
}
}
},
"integrations_shell_section_title" : { "integrations_shell_section_title" : {
"extractionState" : "manual", "extractionState" : "manual",
"localizations" : { "localizations" : {
@@ -5369,18 +5347,6 @@
} }
} }
}, },
"translationCredits" : {
"comment" : "Translated Into Language By\nFirst Translator, Second Translator, Third Translator",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : " "
}
}
}
},
"unnamed_secret" : { "unnamed_secret" : {
"extractionState" : "manual", "extractionState" : "manual",
"localizations" : { "localizations" : {

View File

@@ -30,7 +30,7 @@ extension SecureEnclave {
SecItemCopyMatching(privateAttributes, &privateUntyped) SecItemCopyMatching(privateAttributes, &privateUntyped)
guard let privateTyped = privateUntyped as? [[CFString: Any]] else { return } guard let privateTyped = privateUntyped as? [[CFString: Any]] else { return }
let migratedPublicKeys = Set(store.secrets.map(\.publicKey)) let migratedPublicKeys = Set(store.secrets.map(\.publicKey))
var migrated = false var migratedAny = false
for key in privateTyped { for key in privateTyped {
let name = key[kSecAttrLabel] as? String ?? String(localized: .unnamedSecret) let name = key[kSecAttrLabel] as? String ?? String(localized: .unnamedSecret)
let id = key[kSecAttrApplicationLabel] as! Data let id = key[kSecAttrApplicationLabel] as! Data
@@ -45,6 +45,7 @@ extension SecureEnclave {
// Best guess. // Best guess.
let auth: AuthenticationRequirement = String(describing: accessControl) let auth: AuthenticationRequirement = String(describing: accessControl)
.contains("DeviceOwnerAuthentication") ? .presenceRequired : .unknown .contains("DeviceOwnerAuthentication") ? .presenceRequired : .unknown
do {
let parsed = try CryptoKit.SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: tokenObjectID) 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)) 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 { guard !migratedPublicKeys.contains(parsed.publicKey.x963Representation) else {
@@ -56,9 +57,12 @@ extension SecureEnclave {
try store.saveKey(tokenObjectID, name: name, attributes: secret.attributes) try store.saveKey(tokenObjectID, name: name, attributes: secret.attributes)
logger.log("Migrated \(name).") logger.log("Migrated \(name).")
try markMigrated(secret: secret, oldID: id) try markMigrated(secret: secret, oldID: id)
migrated = true migratedAny = true
} catch {
logger.error("Failed to migrate \(name): \(error).")
} }
if migrated { }
if migratedAny {
store.reloadSecrets() store.reloadSecrets()
} }
} }

View File

@@ -146,6 +146,6 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View {
} }
#Preview { //#Preview {
CreateSecretView(store: Preview.StoreModifiable()) { _ in } // CreateSecretView(store: Preview.StoreModifiable()) { _ in }
} //}

View File

@@ -57,15 +57,10 @@ struct EmptyStoreModifiableView: View {
} }
} }
#if DEBUG
struct EmptyStoreModifiableView_Previews: PreviewProvider { #Preview {
static var previews: some View {
Group {
EmptyStoreImmutableView() EmptyStoreImmutableView()
EmptyStoreModifiableView()
}
}
} }
#Preview {
#endif EmptyStoreModifiableView()
}

View File

@@ -13,12 +13,7 @@ struct NoStoresView: View {
} }
#if DEBUG #Preview {
struct NoStoresView_Previews: PreviewProvider {
static var previews: some View {
NoStoresView() NoStoresView()
}
} }
#endif

View File

@@ -37,6 +37,6 @@ struct SecretDetailView<SecretType: Secret>: View {
} }
#Preview { //#Preview {
SecretDetailView(secret: Preview.Secret(name: "Demonstration Secret")) // SecretDetailView(secret: Preview.Secret(name: "Demonstration Secret"))
} //}

View File

@@ -143,11 +143,11 @@ struct AgentNotRunningView: View {
} }
#Preview { //#Preview {
AgentStatusView() // AgentStatusView()
.environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: false)) // .environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: false))
} //}
#Preview { //#Preview {
AgentStatusView() // AgentStatusView()
.environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: true, process: .current)) // .environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: true, process: .current))
} //}

View File

@@ -198,25 +198,17 @@ extension ContentView {
} }
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
// Empty on modifiable and nonmodifiable
ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
.environment(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]))
.environment(PreviewUpdater())
// 5 items on modifiable and nonmodifiable
ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
.environment(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]))
.environment(PreviewUpdater())
}
}
}
#endif
//#Preview {
// // Empty on modifiable and nonmodifiable
// ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
// .environment(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]))
// .environment(PreviewUpdater())
//}
//
//#Preview {
// // 5 items on modifiable and nonmodifiable
// ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
// .environment(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]))
// .environment(PreviewUpdater())
//}

View File

@@ -163,17 +163,12 @@ fileprivate struct BackgroundViewModifier: ViewModifier {
} }
#if DEBUG #Preview {
struct CopyableView_Previews: PreviewProvider {
static var previews: some View {
Group {
CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "figure.wave"), text: "Hello world.") CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "figure.wave"), text: "Hello world.")
.padding() .padding()
CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "figure.wave"), text: "Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. ")
.padding()
}
}
} }
#endif #Preview {
CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "figure.wave"), text: "Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. ")
.padding()
}