update name to be cursor internal

This commit is contained in:
Roy Xu 2025-12-09 16:30:01 -05:00
parent 303c5fc2a1
commit 625a605cc7
No known key found for this signature in database
29 changed files with 297 additions and 326 deletions

View File

@ -58,7 +58,7 @@ jobs:
CLI_BINARY="Sources/Packages/.build/release/SecretiveCLI" CLI_BINARY="Sources/Packages/.build/release/SecretiveCLI"
ENTITLEMENTS="Sources/Packages/Sources/SecretiveCLI/SecretiveCLI.entitlements" ENTITLEMENTS="Sources/Packages/Sources/SecretiveCLI/SecretiveCLI.entitlements"
IDENTITY=$(security find-identity -p codesigning -v 2>/dev/null | grep "Developer ID Application" | head -n1 | awk -F'"' '{print $2}') IDENTITY=$(security find-identity -p codesigning -v 2>/dev/null | grep "Developer ID Application" | head -n1 | awk -F'"' '{print $2}')
codesign --force --options runtime --sign "$IDENTITY" --identifier "com.maxgoedjen.Secretive.Host" --entitlements "$ENTITLEMENTS" "$CLI_BINARY" codesign --force --options runtime --sign "$IDENTITY" --identifier "com.cursorinternal.Secretive.Host" --entitlements "$ENTITLEMENTS" "$CLI_BINARY"
- name: Prepare Artifact Folder - name: Prepare Artifact Folder
run: | run: |
mkdir -p Artifact/App mkdir -p Artifact/App
@ -67,32 +67,32 @@ jobs:
cp Sources/Packages/.build/release/SecretiveCLI Artifact/CLI/secretive cp Sources/Packages/.build/release/SecretiveCLI Artifact/CLI/secretive
- name: Build Installer Package - name: Build Installer Package
run: | run: |
pkgbuild --root Artifact/App --install-location /Applications --identifier com.maxgoedjen.Secretive.app --version 1.0 App.pkg pkgbuild --root Artifact/App --install-location /Applications --identifier com.cursorinternal.Secretive.app --version 1.0 App.pkg
pkgbuild --root Artifact/CLI --install-location /usr/local/bin --identifier com.maxgoedjen.Secretive.cli --version 1.0 CLI.pkg pkgbuild --root Artifact/CLI --install-location /usr/local/bin --identifier com.cursorinternal.Secretive.cli --version 1.0 CLI.pkg
cat > distribution.xml << 'EOF' cat > distribution.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<installer-gui-script minSpecVersion="2"> <installer-gui-script minSpecVersion="2">
<title>Secretive</title> <title>Secretive</title>
<organization>com.maxgoedjen</organization> <organization>com.cursorinternal</organization>
<domains enable_localSystem="true"/> <domains enable_localSystem="true"/>
<options customize="never" require-scripts="false" rootVolumeOnly="true"/> <options customize="never" require-scripts="false" rootVolumeOnly="true"/>
<pkg-ref id="com.maxgoedjen.Secretive.app"/> <pkg-ref id="com.cursorinternal.Secretive.app"/>
<pkg-ref id="com.maxgoedjen.Secretive.cli"/> <pkg-ref id="com.cursorinternal.Secretive.cli"/>
<choices-outline> <choices-outline>
<line choice="default"> <line choice="default">
<line choice="com.maxgoedjen.Secretive.app"/> <line choice="com.cursorinternal.Secretive.app"/>
<line choice="com.maxgoedjen.Secretive.cli"/> <line choice="com.cursorinternal.Secretive.cli"/>
</line> </line>
</choices-outline> </choices-outline>
<choice id="default"/> <choice id="default"/>
<choice id="com.maxgoedjen.Secretive.app" visible="false"> <choice id="com.cursorinternal.Secretive.app" visible="false">
<pkg-ref id="com.maxgoedjen.Secretive.app"/> <pkg-ref id="com.cursorinternal.Secretive.app"/>
</choice> </choice>
<choice id="com.maxgoedjen.Secretive.cli" visible="false"> <choice id="com.cursorinternal.Secretive.cli" visible="false">
<pkg-ref id="com.maxgoedjen.Secretive.cli"/> <pkg-ref id="com.cursorinternal.Secretive.cli"/>
</choice> </choice>
<pkg-ref id="com.maxgoedjen.Secretive.app" version="1.0" onConclusion="none">App.pkg</pkg-ref> <pkg-ref id="com.cursorinternal.Secretive.app" version="1.0" onConclusion="none">App.pkg</pkg-ref>
<pkg-ref id="com.maxgoedjen.Secretive.cli" version="1.0" onConclusion="none">CLI.pkg</pkg-ref> <pkg-ref id="com.cursorinternal.Secretive.cli" version="1.0" onConclusion="none">CLI.pkg</pkg-ref>
</installer-gui-script> </installer-gui-script>
EOF EOF
productbuild --distribution distribution.xml --package-path . Secretive-unsigned.pkg productbuild --distribution distribution.xml --package-path . Secretive-unsigned.pkg

View File

@ -22,7 +22,22 @@ jobs:
AGENT_PROFILE_DATA: ${{ secrets.AGENT_PROFILE_DATA }} AGENT_PROFILE_DATA: ${{ secrets.AGENT_PROFILE_DATA }}
APPLE_API_KEY_DATA: ${{ secrets.APPLE_API_KEY_DATA }} APPLE_API_KEY_DATA: ${{ secrets.APPLE_API_KEY_DATA }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
run: ./.github/scripts/signing.sh run: |
echo $SIGNING_DATA | base64 -d -o Signing.p12
security create-keychain -p ci ci.keychain
security default-keychain -s ci.keychain
security list-keychains -s ci.keychain
security import ./Signing.p12 -k ci.keychain -P $SIGNING_PASSWORD -A
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k ci ci.keychain
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
echo $HOST_PROFILE_DATA | base64 -d -o Host.provisionprofile
HOST_UUID=$(grep UUID -A1 -a Host.provisionprofile | grep -io "[-A-F0-9]\{36\}")
cp Host.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/$HOST_UUID.provisionprofile
echo $AGENT_PROFILE_DATA | base64 -d -o Agent.provisionprofile
AGENT_UUID=$(grep UUID -A1 -a Agent.provisionprofile | grep -io "[-A-F0-9]\{36\}")
cp Agent.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/$AGENT_UUID.provisionprofile
mkdir ~/.private_keys
echo -n "$APPLE_API_KEY_DATA" > ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8
- name: Set Environment - name: Set Environment
run: sudo xcrun xcode-select -s /Applications/Xcode_26.1.app run: sudo xcrun xcode-select -s /Applications/Xcode_26.1.app
- name: Update Build Number - name: Update Build Number
@ -33,32 +48,70 @@ jobs:
sed -i '' -e "s/GITHUB_CI_VERSION/0.0.0_oneoff-$DATE/g" Sources/Config/Config.xcconfig sed -i '' -e "s/GITHUB_CI_VERSION/0.0.0_oneoff-$DATE/g" Sources/Config/Config.xcconfig
sed -i '' -e "s/GITHUB_BUILD_NUMBER/1.$RUN_ID/g" Sources/Config/Config.xcconfig sed -i '' -e "s/GITHUB_BUILD_NUMBER/1.$RUN_ID/g" Sources/Config/Config.xcconfig
sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Config/Config.xcconfig sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Config/Config.xcconfig
- name: Build - name: Build App
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: Move to Artifact Folder - name: Build CLI
run: mkdir Artifact; cp -r Archive.xcarchive/Products/Applications/Secretive.app Artifact run: swift build -c release --product SecretiveCLI --package-path Sources/Packages
- name: Upload App to Artifacts - name: Codesign CLI
id: upload
uses: actions/upload-artifact@v4
with:
name: Secretive
path: Artifact
- name: Download Zipped Artifact
id: download
env:
ZIP_ID: ${{ steps.upload.outputs.artifact-id }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
curl -L -H "Authorization: Bearer $GITHUB_TOKEN" -L \ CLI_BINARY="Sources/Packages/.build/release/SecretiveCLI"
https://api.github.com/repos/maxgoedjen/secretive/actions/artifacts/$ZIP_ID/zip > Secretive.zip ENTITLEMENTS="Sources/Packages/Sources/SecretiveCLI/SecretiveCLI.entitlements"
IDENTITY=$(security find-identity -p codesigning -v 2>/dev/null | grep "Developer ID Application" | head -n1 | awk -F'"' '{print $2}')
codesign --force --options runtime --sign "$IDENTITY" --identifier "com.cursorinternal.Secretive.Host" --entitlements "$ENTITLEMENTS" "$CLI_BINARY"
- name: Prepare Artifact Folder
run: |
mkdir -p Artifact/App
mkdir -p Artifact/CLI
cp -r Archive.xcarchive/Products/Applications/Secretive.app Artifact/App/
cp Sources/Packages/.build/release/SecretiveCLI Artifact/CLI/secretive
- name: Build Installer Package
run: |
pkgbuild --root Artifact/App --install-location /Applications --identifier com.cursorinternal.Secretive.app --version 1.0 App.pkg
pkgbuild --root Artifact/CLI --install-location /usr/local/bin --identifier com.cursorinternal.Secretive.cli --version 1.0 CLI.pkg
cat > distribution.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<installer-gui-script minSpecVersion="2">
<title>Secretive</title>
<organization>com.cursorinternal</organization>
<domains enable_localSystem="true"/>
<options customize="never" require-scripts="false" rootVolumeOnly="true"/>
<pkg-ref id="com.cursorinternal.Secretive.app"/>
<pkg-ref id="com.cursorinternal.Secretive.cli"/>
<choices-outline>
<line choice="default">
<line choice="com.cursorinternal.Secretive.app"/>
<line choice="com.cursorinternal.Secretive.cli"/>
</line>
</choices-outline>
<choice id="default"/>
<choice id="com.cursorinternal.Secretive.app" visible="false">
<pkg-ref id="com.cursorinternal.Secretive.app"/>
</choice>
<choice id="com.cursorinternal.Secretive.cli" visible="false">
<pkg-ref id="com.cursorinternal.Secretive.cli"/>
</choice>
<pkg-ref id="com.cursorinternal.Secretive.app" version="1.0" onConclusion="none">App.pkg</pkg-ref>
<pkg-ref id="com.cursorinternal.Secretive.cli" version="1.0" onConclusion="none">CLI.pkg</pkg-ref>
</installer-gui-script>
EOF
productbuild --distribution distribution.xml --package-path . Secretive-unsigned.pkg
INSTALLER_IDENTITY=$(security find-identity -p basic -v 2>/dev/null | grep "Developer ID Installer" | head -n1 | awk -F'"' '{print $2}')
productsign --sign "$INSTALLER_IDENTITY" Secretive-unsigned.pkg Secretive.pkg
- 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 --wait Secretive.pkg
xcrun stapler staple Secretive.pkg
- name: Upload Installer to Artifacts
id: upload
uses: actions/upload-artifact@v4
with:
name: Secretive.pkg
path: Secretive.pkg
- name: Attest - name: Attest
id: attest id: attest
uses: actions/attest-build-provenance@v2 uses: actions/attest-build-provenance@v2
with: with:
subject-name: "Secretive.zip" subject-path: "Secretive.pkg"
subject-digest: sha256:${{ steps.upload.outputs.artifact-digest }}

View File

@ -96,7 +96,7 @@ jobs:
CLI_BINARY="Sources/Packages/.build/release/SecretiveCLI" CLI_BINARY="Sources/Packages/.build/release/SecretiveCLI"
ENTITLEMENTS="Sources/Packages/Sources/SecretiveCLI/SecretiveCLI.entitlements" ENTITLEMENTS="Sources/Packages/Sources/SecretiveCLI/SecretiveCLI.entitlements"
IDENTITY=$(security find-identity -p codesigning -v 2>/dev/null | grep "Developer ID Application" | head -n1 | awk -F'"' '{print $2}') IDENTITY=$(security find-identity -p codesigning -v 2>/dev/null | grep "Developer ID Application" | head -n1 | awk -F'"' '{print $2}')
codesign --force --options runtime --sign "$IDENTITY" --identifier "com.maxgoedjen.Secretive.Host" --entitlements "$ENTITLEMENTS" "$CLI_BINARY" codesign --force --options runtime --sign "$IDENTITY" --identifier "com.cursorinternal.Secretive.Host" --entitlements "$ENTITLEMENTS" "$CLI_BINARY"
- name: Prepare Artifact Folder - name: Prepare Artifact Folder
run: | run: |
mkdir -p Artifact/App mkdir -p Artifact/App
@ -105,32 +105,32 @@ jobs:
cp Sources/Packages/.build/release/SecretiveCLI Artifact/CLI/secretive cp Sources/Packages/.build/release/SecretiveCLI Artifact/CLI/secretive
- name: Build Installer Package - name: Build Installer Package
run: | run: |
pkgbuild --root Artifact/App --install-location /Applications --identifier com.maxgoedjen.Secretive.app --version 1.0 App.pkg pkgbuild --root Artifact/App --install-location /Applications --identifier com.cursorinternal.Secretive.app --version 1.0 App.pkg
pkgbuild --root Artifact/CLI --install-location /usr/local/bin --identifier com.maxgoedjen.Secretive.cli --version 1.0 CLI.pkg pkgbuild --root Artifact/CLI --install-location /usr/local/bin --identifier com.cursorinternal.Secretive.cli --version 1.0 CLI.pkg
cat > distribution.xml << 'EOF' cat > distribution.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<installer-gui-script minSpecVersion="2"> <installer-gui-script minSpecVersion="2">
<title>Secretive</title> <title>Secretive</title>
<organization>com.maxgoedjen</organization> <organization>com.cursorinternal</organization>
<domains enable_localSystem="true"/> <domains enable_localSystem="true"/>
<options customize="never" require-scripts="false" rootVolumeOnly="true"/> <options customize="never" require-scripts="false" rootVolumeOnly="true"/>
<pkg-ref id="com.maxgoedjen.Secretive.app"/> <pkg-ref id="com.cursorinternal.Secretive.app"/>
<pkg-ref id="com.maxgoedjen.Secretive.cli"/> <pkg-ref id="com.cursorinternal.Secretive.cli"/>
<choices-outline> <choices-outline>
<line choice="default"> <line choice="default">
<line choice="com.maxgoedjen.Secretive.app"/> <line choice="com.cursorinternal.Secretive.app"/>
<line choice="com.maxgoedjen.Secretive.cli"/> <line choice="com.cursorinternal.Secretive.cli"/>
</line> </line>
</choices-outline> </choices-outline>
<choice id="default"/> <choice id="default"/>
<choice id="com.maxgoedjen.Secretive.app" visible="false"> <choice id="com.cursorinternal.Secretive.app" visible="false">
<pkg-ref id="com.maxgoedjen.Secretive.app"/> <pkg-ref id="com.cursorinternal.Secretive.app"/>
</choice> </choice>
<choice id="com.maxgoedjen.Secretive.cli" visible="false"> <choice id="com.cursorinternal.Secretive.cli" visible="false">
<pkg-ref id="com.maxgoedjen.Secretive.cli"/> <pkg-ref id="com.cursorinternal.Secretive.cli"/>
</choice> </choice>
<pkg-ref id="com.maxgoedjen.Secretive.app" version="1.0" onConclusion="none">App.pkg</pkg-ref> <pkg-ref id="com.cursorinternal.Secretive.app" version="1.0" onConclusion="none">App.pkg</pkg-ref>
<pkg-ref id="com.maxgoedjen.Secretive.cli" version="1.0" onConclusion="none">CLI.pkg</pkg-ref> <pkg-ref id="com.cursorinternal.Secretive.cli" version="1.0" onConclusion="none">CLI.pkg</pkg-ref>
</installer-gui-script> </installer-gui-script>
EOF EOF
productbuild --distribution distribution.xml --package-path . Secretive-unsigned.pkg productbuild --distribution distribution.xml --package-path . Secretive-unsigned.pkg

2
FAQ.md
View File

@ -54,7 +54,7 @@ Secretive checks in with GitHub's releases API to check if there's a new version
### How do I uninstall Secretive? ### How do I uninstall Secretive?
Drag Secretive.app to the trash and remove `~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent`. `SecretAgent` may continue running until you quit it or reboot. Drag Secretive.app to the trash and remove `~/Library/Containers/com.cursorinternal.Secretive.SecretAgent`. `SecretAgent` may continue running until you quit it or reboot.
### I have a security issue ### I have a security issue

View File

@ -1,5 +1,11 @@
# Creates a dev package containing the Secretive app and CLI # Creates a dev package containing the Secretive app and CLI
# Usage: make # Usage:
# make - Build unsigned (no keychain/Secure Enclave access)
# make SIGN=1 TEAM=XXXXXX - Build with development signing (enables keychain access)
#
# To find your team ID, run:
# security find-identity -v -p codesigning
# Look for "Apple Development: Your Name (TEAMID)" - the TEAMID is in parentheses at the end
PROJECT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) PROJECT_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
BUILD_DIR := $(PROJECT_DIR)/build BUILD_DIR := $(PROJECT_DIR)/build
@ -16,26 +22,51 @@ FINAL_PKG := $(BUILD_DIR)/Secretive-dev-unsigned.pkg
XCODEBUILD := xcodebuild -project $(PROJECT_DIR)/Sources/Secretive.xcodeproj XCODEBUILD := xcodebuild -project $(PROJECT_DIR)/Sources/Secretive.xcodeproj
# Signing configuration
# SIGN_IDENTITY can be set to a specific identity, otherwise defaults to "Apple Development"
SIGN_IDENTITY ?= Apple Development
ifdef SIGN
CODE_SIGN_ARGS := CODE_SIGNING_ALLOWED=YES CODE_SIGNING_REQUIRED=YES CODE_SIGN_STYLE=Automatic
ifdef TEAM
CODE_SIGN_ARGS += DEVELOPMENT_TEAM=$(TEAM)
endif
else
CODE_SIGN_ARGS := CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY=""
endif
.PHONY: all clean .PHONY: all clean
all: $(FINAL_PKG) all: $(FINAL_PKG)
@echo "Built: $(FINAL_PKG)" @echo "Built: $(FINAL_PKG)"
# Validate TEAM is set when SIGN is enabled
ifdef SIGN
ifndef TEAM
$(error SIGN=1 requires TEAM=<your-team-id>. Find it with: security find-identity -v -p codesigning)
endif
endif
$(ARCHIVE): $(ARCHIVE):
@mkdir -p $(BUILD_DIR) @mkdir -p $(BUILD_DIR)
$(XCODEBUILD) -scheme Secretive -configuration Release CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" -archivePath $(ARCHIVE) archive $(XCODEBUILD) -scheme Secretive -configuration Release $(CODE_SIGN_ARGS) -archivePath $(ARCHIVE) archive
$(APP_BUNDLE): $(ARCHIVE) $(APP_BUNDLE): $(ARCHIVE)
@rm -rf $(APP_BUNDLE) @rm -rf $(APP_BUNDLE)
cp -R $(ARCHIVE)/Products/Applications/Secretive.app $(APP_BUNDLE) cp -R $(ARCHIVE)/Products/Applications/Secretive.app $(APP_BUNDLE)
CLI_ENTITLEMENTS_SRC := $(PROJECT_DIR)/Sources/Packages/Sources/SecretiveCLI/SecretiveCLI.entitlements
CLI_ENTITLEMENTS := $(BUILD_DIR)/SecretiveCLI.entitlements
$(CLI_BIN): $(CLI_BIN):
@mkdir -p $(BUILD_DIR) @mkdir -p $(BUILD_DIR)
cd $(PROJECT_DIR)/Sources/Packages && xcodebuild -scheme SecretiveCLI -configuration Release \ swift build -c release --product SecretiveCLI --package-path $(PROJECT_DIR)/Sources/Packages
-destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY="" \ cp $(PROJECT_DIR)/Sources/Packages/.build/release/SecretiveCLI $(CLI_BIN)
SYMROOT=$(BUILD_DIR)/xcode-cli build ifdef SIGN
cp $(BUILD_DIR)/xcode-cli/Release/SecretiveCLI $(CLI_BIN) @echo "Signing CLI binary with team $(TEAM)..."
cp -R $(BUILD_DIR)/xcode-cli/Release/*.bundle $(BUILD_DIR)/ 2>/dev/null || true @sed 's/$$(AppIdentifierPrefix)/$(TEAM)./g' $(CLI_ENTITLEMENTS_SRC) > $(CLI_ENTITLEMENTS)
codesign --force --sign "$(SIGN_IDENTITY)" --entitlements $(CLI_ENTITLEMENTS) $(CLI_BIN)
endif
$(APP_ROOT): $(APP_BUNDLE) $(APP_ROOT): $(APP_BUNDLE)
@rm -rf $(APP_ROOT) @rm -rf $(APP_ROOT)
@ -48,10 +79,10 @@ $(CLI_ROOT): $(CLI_BIN)
cp $(CLI_BIN) $(CLI_ROOT)/secretive cp $(CLI_BIN) $(CLI_ROOT)/secretive
$(APP_PKG): $(APP_ROOT) $(APP_PKG): $(APP_ROOT)
pkgbuild --root $(APP_ROOT) --install-location /Applications --identifier com.maxgoedjen.Secretive.app --version 0.0.0-dev $(APP_PKG) pkgbuild --root $(APP_ROOT) --install-location /Applications --identifier com.cursorinternal.Secretive.app --version 0.0.0-dev $(APP_PKG)
$(CLI_PKG): $(CLI_ROOT) $(CLI_PKG): $(CLI_ROOT)
pkgbuild --root $(CLI_ROOT) --install-location /usr/local/bin --identifier com.maxgoedjen.Secretive.cli --version 0.0.0-dev $(CLI_PKG) pkgbuild --root $(CLI_ROOT) --install-location /usr/local/bin --identifier com.cursorinternal.Secretive.cli --version 0.0.0-dev $(CLI_PKG)
$(DIST): $(DIST):
@mkdir -p $(BUILD_DIR) @mkdir -p $(BUILD_DIR)
@ -59,31 +90,32 @@ $(DIST):
'<?xml version="1.0" encoding="utf-8"?>' \ '<?xml version="1.0" encoding="utf-8"?>' \
'<installer-gui-script minSpecVersion="2">' \ '<installer-gui-script minSpecVersion="2">' \
' <title>Secretive (Dev)</title>' \ ' <title>Secretive (Dev)</title>' \
' <organization>com.maxgoedjen</organization>' \ ' <organization>com.cursorinternal</organization>' \
' <domains enable_localSystem="true"/>' \ ' <domains enable_localSystem="true"/>' \
' <options customize="never" require-scripts="false" rootVolumeOnly="true"/>' \ ' <options customize="never" require-scripts="false" rootVolumeOnly="true"/>' \
' <pkg-ref id="com.maxgoedjen.Secretive.app"/>' \ ' <pkg-ref id="com.cursorinternal.Secretive.app"/>' \
' <pkg-ref id="com.maxgoedjen.Secretive.cli"/>' \ ' <pkg-ref id="com.cursorinternal.Secretive.cli"/>' \
' <choices-outline>' \ ' <choices-outline>' \
' <line choice="default">' \ ' <line choice="default">' \
' <line choice="com.maxgoedjen.Secretive.app"/>' \ ' <line choice="com.cursorinternal.Secretive.app"/>' \
' <line choice="com.maxgoedjen.Secretive.cli"/>' \ ' <line choice="com.cursorinternal.Secretive.cli"/>' \
' </line>' \ ' </line>' \
' </choices-outline>' \ ' </choices-outline>' \
' <choice id="default"/>' \ ' <choice id="default"/>' \
' <choice id="com.maxgoedjen.Secretive.app" visible="false">' \ ' <choice id="com.cursorinternal.Secretive.app" visible="false">' \
' <pkg-ref id="com.maxgoedjen.Secretive.app"/>' \ ' <pkg-ref id="com.cursorinternal.Secretive.app"/>' \
' </choice>' \ ' </choice>' \
' <choice id="com.maxgoedjen.Secretive.cli" visible="false">' \ ' <choice id="com.cursorinternal.Secretive.cli" visible="false">' \
' <pkg-ref id="com.maxgoedjen.Secretive.cli"/>' \ ' <pkg-ref id="com.cursorinternal.Secretive.cli"/>' \
' </choice>' \ ' </choice>' \
' <pkg-ref id="com.maxgoedjen.Secretive.app" version="0.0.0-dev" onConclusion="none">App.pkg</pkg-ref>' \ ' <pkg-ref id="com.cursorinternal.Secretive.app" version="0.0.0-dev" onConclusion="none">App.pkg</pkg-ref>' \
' <pkg-ref id="com.maxgoedjen.Secretive.cli" version="0.0.0-dev" onConclusion="none">CLI.pkg</pkg-ref>' \ ' <pkg-ref id="com.cursorinternal.Secretive.cli" version="0.0.0-dev" onConclusion="none">CLI.pkg</pkg-ref>' \
'</installer-gui-script>' \ '</installer-gui-script>' \
> $(DIST) > $(DIST)
$(FINAL_PKG): $(APP_PKG) $(CLI_PKG) $(DIST) $(FINAL_PKG): $(APP_PKG) $(CLI_PKG) $(DIST)
productbuild --distribution $(DIST) --package-path $(BUILD_DIR) $(FINAL_PKG) productbuild --distribution $(DIST) --package-path $(BUILD_DIR) $(FINAL_PKG)
@rm -rf $(ARCHIVE) $(APP_BUNDLE) $(APP_ROOT) $(APP_PKG) $(CLI_BIN) $(CLI_ROOT) $(CLI_PKG) $(DIST)
clean: clean:
rm -rf $(BUILD_DIR) rm -rf $(BUILD_DIR)

View File

@ -37,7 +37,7 @@ let package = Package(
targets: [ targets: [
.target( .target(
name: "SecretKit", name: "SecretKit",
dependencies: [], dependencies: ["Localizations"],
resources: [localization], resources: [localization],
swiftSettings: swiftSettings, swiftSettings: swiftSettings,
), ),
@ -54,13 +54,13 @@ let package = Package(
), ),
.target( .target(
name: "SecureEnclaveSecretKit", name: "SecureEnclaveSecretKit",
dependencies: ["SecretKit", "Localizations"], dependencies: ["SecretKit"],
resources: [localization], resources: [localization],
swiftSettings: swiftSettings, swiftSettings: swiftSettings,
), ),
.target( .target(
name: "SmartCardSecretKit", name: "SmartCardSecretKit",
dependencies: ["SecretKit", "Localizations"], dependencies: ["SecretKit"],
resources: [localization], resources: [localization],
swiftSettings: swiftSettings, swiftSettings: swiftSettings,
), ),
@ -97,12 +97,10 @@ let package = Package(
.executableTarget( .executableTarget(
name: "SecretiveCLI", name: "SecretiveCLI",
dependencies: [ dependencies: [
"SecretAgentKit",
"SecureEnclaveSecretKit", "SecureEnclaveSecretKit",
"SmartCardSecretKit", "SmartCardSecretKit",
"SecretKit", "SecretKit",
"Common", "Common",
"Localizations",
], ],
exclude: ["Generated"], exclude: ["Generated"],
swiftSettings: swiftSettings, swiftSettings: swiftSettings,

View File

@ -47,7 +47,7 @@ import XPCWrappers
/// Manually trigger an update check. /// Manually trigger an update check.
public func checkForUpdates() async throws { public func checkForUpdates() async throws {
let session = try await XPCTypedSession<[Release], Never>(serviceName: "com.maxgoedjen.Secretive.SecretiveUpdater") let session = try await XPCTypedSession<[Release], Never>(serviceName: "com.cursorinternal.Secretive.SecretiveUpdater")
await evaluate(releases: try await session.send()) await evaluate(releases: try await session.send())
session.complete() session.complete()
} }
@ -95,7 +95,7 @@ extension Updater {
/// The user defaults used to store user ignore state. /// The user defaults used to store user ignore state.
var defaults: UserDefaults { var defaults: UserDefaults {
UserDefaults(suiteName: "com.maxgoedjen.Secretive.updater.ignorelist")! UserDefaults(suiteName: "com.cursorinternal.Secretive.updater.ignorelist")!
} }
} }

View File

@ -12,7 +12,7 @@ public final class Agent: Sendable {
private let publicKeyWriter = OpenSSHPublicKeyWriter() private let publicKeyWriter = OpenSSHPublicKeyWriter()
private let signatureWriter = OpenSSHSignatureWriter() private let signatureWriter = OpenSSHSignatureWriter()
private let certificateHandler = OpenSSHCertificateHandler() private let certificateHandler = OpenSSHCertificateHandler()
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "Agent") private let logger = Logger(subsystem: "com.cursorinternal.secretive.secretagent", category: "Agent")
/// Initializes an agent with a store list and a witness. /// Initializes an agent with a store list and a witness.
/// - Parameters: /// - Parameters:

View File

@ -6,7 +6,7 @@ import SecretKit
public actor OpenSSHCertificateHandler: Sendable { public actor OpenSSHCertificateHandler: Sendable {
private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: URL.homeDirectory) private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: URL.homeDirectory)
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "OpenSSHCertificateHandler") private let logger = Logger(subsystem: "com.cursorinternal.secretive.secretagent", category: "OpenSSHCertificateHandler")
private let writer = OpenSSHPublicKeyWriter() private let writer = OpenSSHPublicKeyWriter()
private var keyBlobsAndNames: [AnySecret: (Data, Data)] = [:] private var keyBlobsAndNames: [AnySecret: (Data, Data)] = [:]

View File

@ -10,7 +10,7 @@ public protocol SSHAgentInputParserProtocol {
public struct SSHAgentInputParser: SSHAgentInputParserProtocol { public struct SSHAgentInputParser: SSHAgentInputParserProtocol {
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "InputParser") private let logger = Logger(subsystem: "com.cursorinternal.secretive.secretagent", category: "InputParser")
public init() { public init() {

View File

@ -18,7 +18,7 @@ public struct SocketController {
private let fileHandle: FileHandle private let fileHandle: FileHandle
/// Logger for the socket controller. /// Logger for the socket controller.
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "SocketController") private let logger = Logger(subsystem: "com.cursorinternal.secretive.secretagent", category: "SocketController")
/// Tracer which determines who originates a socket connection. /// Tracer which determines who originates a socket connection.
private let requestTracer = SigningRequestTracer() private let requestTracer = SigningRequestTracer()
@ -74,7 +74,7 @@ extension SocketController {
private let messagesContinuation: AsyncStream<Data>.Continuation private let messagesContinuation: AsyncStream<Data>.Continuation
/// A logger for the session. /// A logger for the session.
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "Session") private let logger = Logger(subsystem: "com.cursorinternal.secretive.secretagent", category: "Session")
/// Initializes a new Session. /// Initializes a new Session.
/// - Parameter fileHandle: The FileHandle used to communicate with the socket. /// - Parameter fileHandle: The FileHandle used to communicate with the socket.

View File

@ -0,0 +1,3 @@
// Copyright Anysphere Inc.
// Re-exports Localizations module so dependent modules can access localization extensions.
@_exported import Localizations

View File

@ -4,7 +4,7 @@ import OSLog
/// Controller responsible for writing public keys to disk, so that they're easily accessible by scripts. /// Controller responsible for writing public keys to disk, so that they're easily accessible by scripts.
public final class PublicKeyFileStoreController: Sendable { public final class PublicKeyFileStoreController: Sendable {
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "PublicKeyFileStoreController") private let logger = Logger(subsystem: "com.cursorinternal.secretive.secretagent", category: "PublicKeyFileStoreController")
private let directory: URL private let directory: URL
private let keyWriter = OpenSSHPublicKeyWriter() private let keyWriter = OpenSSHPublicKeyWriter()

View File

@ -96,8 +96,8 @@ public struct KeyAvailability: Sendable {
extension NSNotification.Name { extension NSNotification.Name {
// Distributed notification that keys were modified out of process (ie, that the management tool added/removed secrets) // Distributed notification that keys were modified out of process (ie, that the management tool added/removed secrets)
public static let secretStoreUpdated = NSNotification.Name("com.maxgoedjen.Secretive.secretStore.updated") public static let secretStoreUpdated = NSNotification.Name("com.cursorinternal.Secretive.secretStore.updated")
// Internal notification that keys were reloaded from the backing store. // Internal notification that keys were reloaded from the backing store.
public static let secretStoreReloaded = NSNotification.Name("com.maxgoedjen.Secretive.secretStore.reloaded") public static let secretStoreReloaded = NSNotification.Name("com.cursorinternal.Secretive.secretStore.reloaded")
} }

View File

@ -1,6 +1,8 @@
# Secretive CLI # Secretive CLI
A command-line interface for Secretive that provides full key management and SSH agent functionality, sharing the same keychain and socket path as the GUI application. A command-line interface companion for Secretive that provides key management capabilities, sharing the same keychain and socket path as the GUI application.
**Note:** The CLI is a helper tool for the main Secretive app. The SSH agent is managed by the Secretive GUI app - the CLI can check its status but does not run its own agent.
## Installation ## Installation
@ -37,7 +39,7 @@ The CLI uses the entitlements file at `SecretiveCLI.entitlements`:
<true/> <true/>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)com.maxgoedjen.Secretive</string> <string>$(AppIdentifierPrefix)com.cursorinternal.Secretive</string>
</array> </array>
</dict> </dict>
</plist> </plist>
@ -51,41 +53,31 @@ Sign the CLI binary with:
codesign --force \ codesign --force \
--sign "Developer ID Application: YOUR_TEAM_NAME" \ --sign "Developer ID Application: YOUR_TEAM_NAME" \
--options runtime \ --options runtime \
--identifier com.maxgoedjen.Secretive.Host \ --identifier com.cursorinternal.Secretive.Host \
--entitlements Sources/Packages/Sources/SecretiveCLI/SecretiveCLI.entitlements \ --entitlements Sources/Packages/Sources/SecretiveCLI/SecretiveCLI.entitlements \
Sources/Packages/.build/release/SecretiveCLI Sources/Packages/.build/release/SecretiveCLI
``` ```
Replace `YOUR_TEAM_NAME` with your actual Developer ID or use your team's signing identity. Replace `YOUR_TEAM_NAME` with your actual Developer ID or use your team's signing identity.
**Important:** The `--identifier` must be `com.maxgoedjen.Secretive.Host` to match the GUI app's bundle identifier, ensuring the CLI can access the same keychain items. **Important:** The `--identifier` must be `com.cursorinternal.Secretive.Host` to match the GUI app's bundle identifier, ensuring the CLI can access the same keychain items.
## Usage ## Usage
### Agent Management ### Agent Management
Install and manage the SSH agent as a launchd service: Check and control Secretive's SSH agent:
```bash ```bash
# Install the agent as a launchd service
secretive agent install
# Start the agent
secretive agent start
# Check agent status # Check agent status
secretive agent status secretive agent status
# Stop the agent # Start the agent (if not already running)
secretive agent stop secretive agent start
# Uninstall the agent
secretive agent uninstall
# Run agent in foreground (for testing)
secretive agent run
``` ```
The SSH agent is bundled with the Secretive GUI app. The `start` command will locate and launch the agent from the installed Secretive.app.
### Key Management ### Key Management
Manage SSH keys stored in the Secure Enclave: Manage SSH keys stored in the Secure Enclave:
@ -110,27 +102,27 @@ secretive key update "My Key Name"
## Socket Path ## Socket Path
The CLI uses the same socket path as the GUI app: The CLI uses the same socket path as the GUI app:
- Production: `~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh` - Production: `~/Library/Containers/com.cursorinternal.Secretive.SecretAgent/Data/socket.ssh`
- Debug: `~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket-debug.ssh` - Debug: `~/Library/Containers/com.cursorinternal.Secretive.SecretAgent/Data/socket-debug.ssh`
Set `SSH_AUTH_SOCK` to this path to use the agent: Set `SSH_AUTH_SOCK` to this path to use the agent:
```bash ```bash
export SSH_AUTH_SOCK=~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh export SSH_AUTH_SOCK=~/Library/Containers/com.cursorinternal.Secretive.SecretAgent/Data/socket.ssh
``` ```
## Keychain Access ## Keychain Access
The CLI shares the same keychain access group as the GUI app (`com.maxgoedjen.Secretive`), allowing it to: The CLI shares the same keychain access group as the GUI app (`com.cursorinternal.Secretive`), allowing it to:
- Access keys created by the GUI app - Access keys created by the GUI app
- Create keys that are accessible by the GUI app - Create keys that are accessible by the GUI app
- Use the same Secure Enclave storage - Use the same Secure Enclave storage
This is achieved by signing the CLI with the same bundle identifier (`com.maxgoedjen.Secretive.Host`) and keychain access group entitlements. This is achieved by signing the CLI with the same bundle identifier (`com.cursorinternal.Secretive.Host`) and keychain access group entitlements.
## Notes ## Notes
- The CLI uses the same `SecretStoreList` setup as the GUI app, including Secure Enclave and Smart Card stores - The CLI uses the same `SecretStoreList` setup as the GUI app, including Secure Enclave and Smart Card stores
- Keys created via CLI will appear in the GUI app and vice versa - Keys created via CLI will appear in the GUI app and vice versa
- The agent can be run either via launchd (recommended) or in foreground mode for testing - The SSH agent runs as part of the Secretive GUI app - use the CLI's `agent status` command to check if it's running
- All key operations require appropriate authentication (Touch ID, Apple Watch, or password) as configured per key - All key operations require appropriate authentication (Touch ID, Apple Watch, or password) as configured per key

View File

@ -6,8 +6,9 @@
<true/> <true/>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)com.maxgoedjen.Secretive</string> <string>$(AppIdentifierPrefix)com.cursorinternal.Secretive</string>
</array> </array>
</dict> </dict>
</plist> </plist>

View File

@ -1,6 +1,5 @@
import Foundation import Foundation
import Darwin import AppKit
import SecretAgentKit
import SecretKit import SecretKit
import SecureEnclaveSecretKit import SecureEnclaveSecretKit
import SmartCardSecretKit import SmartCardSecretKit
@ -9,7 +8,7 @@ import OSLog
@main @main
struct SecretiveCLI { struct SecretiveCLI {
private static let logger = Logger(subsystem: "com.maxgoedjen.secretive.cli", category: "CLI") private static let logger = Logger(subsystem: "com.cursorinternal.secretive.cli", category: "CLI")
static func main() async { static func main() async {
let args = Array(CommandLine.arguments.dropFirst()) let args = Array(CommandLine.arguments.dropFirst())
@ -46,13 +45,8 @@ struct SecretiveCLI {
Usage: secretive-cli <command> [options] Usage: secretive-cli <command> [options]
Commands: Commands:
agent <subcommand> Manage SSH agent agent status Check if Secretive's SSH agent is running
install Install agent as launchd service agent start Start Secretive's SSH agent
uninstall Uninstall agent from launchd
start Start the agent service
stop Stop the agent service
status Check agent status
run Run agent in foreground (for testing)
key <subcommand> Manage SSH keys key <subcommand> Manage SSH keys
generate [name] Generate a new key (default: "Secretive Key") generate [name] Generate a new key (default: "Secretive Key")
@ -70,211 +64,109 @@ struct SecretiveCLI {
extension SecretiveCLI { extension SecretiveCLI {
private static let agentBundleID = "com.cursorinternal.Secretive.SecretAgent"
private static let secretiveBundleID = "com.cursorinternal.Secretive.Host"
static func handleAgentCommand(args: [String]) async throws { static func handleAgentCommand(args: [String]) async throws {
guard let subcommand = args.first else { guard let subcommand = args.first else {
print("Agent subcommand required: install, uninstall, start, stop, status, or run") print("Agent subcommand required: status, start")
exit(1) exit(1)
} }
switch subcommand { switch subcommand {
case "install":
try await installAgent()
case "uninstall":
try await uninstallAgent()
case "start":
try await startAgent()
case "stop":
try await stopAgent()
case "status": case "status":
try await checkAgentStatus() try await checkAgentStatus()
case "run": case "start":
try await runAgent() try await startAgent()
default: default:
print("Unknown agent subcommand: \(subcommand)") print("Unknown agent subcommand: \(subcommand)")
print("Available: status, start")
exit(1) exit(1)
} }
} }
static func installAgent() async throws { static func checkAgentStatus() async throws {
let plistPath = launchdPlistPath // Check if the main Secretive app's SecretAgent is running
let plistDir = (plistPath as NSString).deletingLastPathComponent let runningAgents = NSRunningApplication.runningApplications(withBundleIdentifier: agentBundleID)
// Create directory if needed if let agent = runningAgents.first {
try FileManager.default.createDirectory(atPath: plistDir, withIntermediateDirectories: true) print("Secretive agent is running")
if let url = agent.bundleURL {
// Get the CLI binary path print(" Path: \(url.path)")
guard let cliPath = Bundle.main.executablePath else { }
throw CLIError("Could not determine CLI binary path") print(" PID: \(agent.processIdentifier)")
// Also check socket
let socketPath = URL.socketPath
if FileManager.default.fileExists(atPath: socketPath) {
print(" Socket: \(socketPath)")
}
} else {
print("Secretive agent is not running")
print("Run 'secretive agent start' to start it")
} }
// Create plist content
let plist: [String: Any] = [
"Label": launchdServiceLabel,
"ProgramArguments": [cliPath, "agent", "run"],
"RunAtLoad": true,
"KeepAlive": true,
"StandardOutPath": "/dev/null",
"StandardErrorPath": "/dev/null",
"EnvironmentVariables": [
"SSH_AUTH_SOCK": socketPath
]
]
let plistData = try PropertyListSerialization.data(fromPropertyList: plist, format: .xml, options: 0)
try plistData.write(to: URL(fileURLWithPath: plistPath))
// Bootstrap the service
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/launchctl")
process.arguments = ["bootstrap", "gui/\(getuid())", plistPath]
try process.run()
process.waitUntilExit()
if process.terminationStatus != 0 {
throw CLIError("Failed to install agent: launchctl bootstrap returned \(process.terminationStatus)")
}
print("Agent installed successfully")
}
static func uninstallAgent() async throws {
let plistPath = launchdPlistPath
// Unbootstrap the service
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/launchctl")
process.arguments = ["bootout", "gui/\(getuid())", launchdServiceLabel]
try process.run()
process.waitUntilExit()
// Remove plist file if it exists
if FileManager.default.fileExists(atPath: plistPath) {
try FileManager.default.removeItem(atPath: plistPath)
}
print("Agent uninstalled successfully")
} }
static func startAgent() async throws { static func startAgent() async throws {
let process = Process() // Check if already running
process.executableURL = URL(fileURLWithPath: "/bin/launchctl") let runningAgents = NSRunningApplication.runningApplications(withBundleIdentifier: agentBundleID)
process.arguments = ["kickstart", "gui/\(getuid())/\(launchdServiceLabel)"] if !runningAgents.isEmpty {
print("Secretive agent is already running")
try process.run() return
process.waitUntilExit()
if process.terminationStatus != 0 {
throw CLIError("Failed to start agent: launchctl kickstart returned \(process.terminationStatus)")
} }
print("Agent started") // Find the SecretAgent app inside the installed Secretive app
} guard let agentURL = findSecretAgentApp() else {
throw CLIError("Could not find Secretive.app. Please ensure Secretive is installed in /Applications or ~/Applications.")
static func stopAgent() async throws { }
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/launchctl")
process.arguments = ["kill", "gui/\(getuid())/\(launchdServiceLabel)"]
try process.run() print("Starting Secretive agent...")
process.waitUntilExit() let config = NSWorkspace.OpenConfiguration()
config.activates = false
print("Agent stopped") do {
} try await NSWorkspace.shared.openApplication(at: agentURL, configuration: config)
// Give it a moment to start
static func checkAgentStatus() async throws { try await Task.sleep(for: .seconds(1))
let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/launchctl") // Verify it started
process.arguments = ["list", launchdServiceLabel] let agents = NSRunningApplication.runningApplications(withBundleIdentifier: agentBundleID)
if !agents.isEmpty {
let pipe = Pipe() print("Secretive agent started successfully")
process.standardOutput = pipe } else {
print("Warning: Agent may not have started. Check Secretive.app for details.")
try process.run() }
process.waitUntilExit() } catch {
throw CLIError("Failed to start agent: \(error.localizedDescription)")
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8) ?? ""
if process.terminationStatus == 0 && !output.isEmpty {
print("Agent is running")
print(output)
} else {
print("Agent is not running")
} }
} }
static func runAgent() async throws { private static func findSecretAgentApp() -> URL? {
logger.info("Starting SSH agent") let fileManager = FileManager.default
// Set up store list // Possible locations for Secretive.app
let storeList: SecretStoreList = await MainActor.run { let searchPaths = [
let list = SecretStoreList() "/Applications/Secretive.app",
let cryptoKit = SecureEnclave.Store() "\(fileManager.homeDirectoryForCurrentUser.path)/Applications/Secretive.app"
let migrator = SecureEnclave.CryptoKitMigrator() ]
try? migrator.migrate(to: cryptoKit)
list.add(store: cryptoKit)
list.add(store: SmartCard.Store())
return list
}
// Create agent (no witness for CLI) for path in searchPaths {
let agent = Agent(storeList: storeList, witness: nil) let secretiveURL = URL(fileURLWithPath: path)
let agentURL = secretiveURL.appendingPathComponent("Contents/Library/LoginItems/SecretAgent.app")
// Set up socket controller if fileManager.fileExists(atPath: agentURL.path) {
let socket = SocketController(path: socketPath) return agentURL
// Set up input parser (use direct parser, not XPC)
let parser = SSHAgentInputParser()
logger.info("SSH agent listening on \(socketPath)")
print("SSH agent running on \(socketPath)")
print("Set SSH_AUTH_SOCK=\(socketPath) to use this agent")
func handleSession(_ session: SocketController.Session) async {
do {
for await message in session.messages {
let request = try parser.parse(data: message)
let response = await agent.handle(request: request, provenance: session.provenance)
try await MainActor.run {
try session.write(response)
}
}
} catch {
logger.error("Session error: \(error.localizedDescription)")
try? session.close()
} }
} }
// Handle sessions // Also try to find via Launch Services
for await session in socket.sessions { if let secretiveURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: secretiveBundleID) {
await handleSession(session) let agentURL = secretiveURL.appendingPathComponent("Contents/Library/LoginItems/SecretAgent.app")
if fileManager.fileExists(atPath: agentURL.path) {
return agentURL
}
} }
}
return nil
// MARK: - Agent Paths
static var socketPath: String {
// Use the same socket path as the GUI app
// This matches URL.socketPath from Common module, which constructs:
// ~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh
let home = FileManager.default.homeDirectoryForCurrentUser.path
let containerPath = "\(home)/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data"
#if DEBUG
return "\(containerPath)/socket-debug.ssh"
#else
return "\(containerPath)/socket.ssh"
#endif
}
static var launchdServiceLabel: String {
"com.maxgoedjen.secretive.cli"
}
static var launchdPlistPath: String {
let home = FileManager.default.homeDirectoryForCurrentUser.path
return "\(home)/Library/LaunchAgents/\(launchdServiceLabel).plist"
} }
} }

View File

@ -9,7 +9,7 @@ extension SecureEnclave {
public struct CryptoKitMigrator { public struct CryptoKitMigrator {
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.migration", category: "CryptoKitMigrator") private let logger = Logger(subsystem: "com.cursorinternal.secretive.migration", category: "CryptoKitMigrator")
public init() { public init() {
} }

View File

@ -287,7 +287,7 @@ extension SecureEnclave.Store {
enum Constants { enum Constants {
static let keyClass = kSecClassGenericPassword as String static let keyClass = kSecClassGenericPassword as String
static let keyTag = Data("com.maxgoedjen.secretive.secureenclave.key".utf8) static let keyTag = Data("com.cursorinternal.secretive.secureenclave.key".utf8)
static let notificationToken = UUID().uuidString static let notificationToken = UUID().uuidString
} }

View File

@ -53,7 +53,7 @@ public final class XPCServiceDelegate: NSObject, NSXPCListenerDelegate {
extension NSError { extension NSError {
private enum Constants { private enum Constants {
static let domain = "com.maxgoedjen.secretive.xpcwrappers" static let domain = "com.cursorinternal.secretive.xpcwrappers"
static let code = -1 static let code = -1
static let dataKey = "underlying" static let dataKey = "underlying"
} }

View File

@ -30,7 +30,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let path = URL.socketPath as String let path = URL.socketPath as String
return SocketController(path: path) return SocketController(path: path)
}() }()
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "AppDelegate") private let logger = Logger(subsystem: "com.cursorinternal.secretive.secretagent", category: "AppDelegate")
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
logger.debug("SecretAgent finished launching") logger.debug("SecretAgent finished launching")

View File

@ -114,18 +114,18 @@ extension Notifier {
enum Constants { enum Constants {
// Update notifications // Update notifications
static let updateCategoryIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.update" static let updateCategoryIdentitifier = "com.cursorinternal.Secretive.SecretAgent.update"
static let criticalUpdateCategoryIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.update.critical" static let criticalUpdateCategoryIdentitifier = "com.cursorinternal.Secretive.SecretAgent.update.critical"
static let updateActionIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.update.updateaction" static let updateActionIdentitifier = "com.cursorinternal.Secretive.SecretAgent.update.updateaction"
static let ignoreActionIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.update.ignoreaction" static let ignoreActionIdentitifier = "com.cursorinternal.Secretive.SecretAgent.update.ignoreaction"
// Authorization persistence notificatoins // Authorization persistence notificatoins
static let persistAuthenticationCategoryIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.persistauthentication" static let persistAuthenticationCategoryIdentitifier = "com.cursorinternal.Secretive.SecretAgent.persistauthentication"
static let doNotPersistActionIdentitifier = "com.maxgoedjen.Secretive.SecretAgent.persistauthentication.donotpersist" static let doNotPersistActionIdentitifier = "com.cursorinternal.Secretive.SecretAgent.persistauthentication.donotpersist"
static let persistForActionIdentitifierPrefix = "com.maxgoedjen.Secretive.SecretAgent.persistauthentication.persist." static let persistForActionIdentitifierPrefix = "com.cursorinternal.Secretive.SecretAgent.persistauthentication.persist."
static let persistSecretIDKey = "com.maxgoedjen.Secretive.SecretAgent.persistauthentication.secretidkey" static let persistSecretIDKey = "com.cursorinternal.Secretive.SecretAgent.persistauthentication.secretidkey"
static let persistStoreIDKey = "com.maxgoedjen.Secretive.SecretAgent.persistauthentication.storeidkey" static let persistStoreIDKey = "com.cursorinternal.Secretive.SecretAgent.persistauthentication.storeidkey"
} }
} }

View File

@ -6,7 +6,7 @@
<true/> <true/>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)com.maxgoedjen.Secretive</string> <string>$(AppIdentifierPrefix)com.cursorinternal.Secretive</string>
</array> </array>
</dict> </dict>
</plist> </plist>

View File

@ -7,12 +7,12 @@ import OSLog
/// Delegates all agent input parsing to an XPC service which wraps OpenSSH /// Delegates all agent input parsing to an XPC service which wraps OpenSSH
public final class XPCAgentInputParser: SSHAgentInputParserProtocol { public final class XPCAgentInputParser: SSHAgentInputParserProtocol {
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "XPCAgentInputParser") private let logger = Logger(subsystem: "com.cursorinternal.secretive.secretagent", category: "XPCAgentInputParser")
private let session: XPCTypedSession<SSHAgent.Request, SSHAgentInputParser.AgentParsingError> private let session: XPCTypedSession<SSHAgent.Request, SSHAgentInputParser.AgentParsingError>
public init() async throws { public init() async throws {
logger.debug("Creating XPCAgentInputParser") logger.debug("Creating XPCAgentInputParser")
session = try await XPCTypedSession(serviceName: "com.maxgoedjen.Secretive.SecretAgentInputParser", warmup: true) session = try await XPCTypedSession(serviceName: "com.cursorinternal.Secretive.SecretAgentInputParser", warmup: true)
logger.debug("XPCAgentInputParser is warmed up.") logger.debug("XPCAgentInputParser is warmed up.")
} }

View File

@ -5,7 +5,7 @@ import SecretAgentKit
final class SecretAgentInputParser: NSObject, XPCProtocol { final class SecretAgentInputParser: NSObject, XPCProtocol {
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.SecretAgentInputParser", category: "SecretAgentInputParser") private let logger = Logger(subsystem: "com.cursorinternal.secretive.SecretAgentInputParser", category: "SecretAgentInputParser")
func process(_ data: Data) async throws -> SSHAgent.Request { func process(_ data: Data) async throws -> SSHAgent.Request {
let parser = SSHAgentInputParser() let parser = SSHAgentInputParser()

View File

@ -960,7 +960,7 @@
); );
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
}; };
@ -1000,7 +1000,7 @@
); );
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Host"; PROVISIONING_PROFILE_SPECIFIER = "Secretive - Host";
}; };
@ -1036,7 +1036,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretiveUpdater; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretiveUpdater;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1076,7 +1076,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretiveUpdater; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretiveUpdater;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1118,7 +1118,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretiveUpdater; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretiveUpdater;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
@ -1150,7 +1150,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgentInputParser; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretAgentInputParser;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1180,7 +1180,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgentInputParser; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretAgentInputParser;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -1212,7 +1212,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgentInputParser; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretAgentInputParser;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
@ -1333,7 +1333,7 @@
); );
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.Host; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.Host;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
}; };
name = Test; name = Test;
@ -1366,7 +1366,7 @@
); );
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
}; };
name = Test; name = Test;
@ -1401,7 +1401,7 @@
); );
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
}; };
name = Debug; name = Debug;
@ -1437,7 +1437,7 @@
); );
MACOSX_DEPLOYMENT_TARGET = 14.0; MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1; MARKETING_VERSION = 1;
PRODUCT_BUNDLE_IDENTIFIER = com.maxgoedjen.Secretive.SecretAgent; PRODUCT_BUNDLE_IDENTIFIER = com.cursorinternal.Secretive.SecretAgent;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent"; PROVISIONING_PROFILE_SPECIFIER = "Secretive - Secret Agent";
}; };

View File

@ -20,7 +20,7 @@ import Common
var running: Bool = false var running: Bool = false
var process: NSRunningApplication? = nil var process: NSRunningApplication? = nil
private let logger = Logger(subsystem: "com.maxgoedjen.secretive", category: "LaunchAgentController") private let logger = Logger(subsystem: "com.cursorinternal.secretive", category: "LaunchAgentController")
private let service = SMAppService.loginItem(identifier: Bundle.agentBundleID) private let service = SMAppService.loginItem(identifier: Bundle.agentBundleID)
nonisolated init() { nonisolated init() {

View File

@ -37,8 +37,8 @@ import AppKit
extension JustUpdatedChecker { extension JustUpdatedChecker {
enum Constants { enum Constants {
static let previousVersionUserDefaultsKey = "com.maxgoedjen.Secretive.lastBuild" static let previousVersionUserDefaultsKey = "com.cursorinternal.Secretive.lastBuild"
static let previousOSVersionUserDefaultsKey = "com.maxgoedjen.Secretive.lastOS" static let previousOSVersionUserDefaultsKey = "com.cursorinternal.Secretive.lastOS"
} }
} }

View File

@ -16,7 +16,7 @@
<true/> <true/>
<key>keychain-access-groups</key> <key>keychain-access-groups</key>
<array> <array>
<string>$(AppIdentifierPrefix)com.maxgoedjen.Secretive</string> <string>$(AppIdentifierPrefix)com.cursorinternal.Secretive</string>
</array> </array>
</dict> </dict>
</plist> </plist>