Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
a41d541
feat: initialize MacSweep project with core scanner, cleaner architec…
lahiruudayakumara Aug 24, 2026
8fc4f00
feat(core): implement core utility modules (logging, byte/date format…
lahiruudayakumara Aug 24, 2026
3b682fc
feat(core): implement safety validation layer and system boundary pro…
lahiruudayakumara Aug 24, 2026
4c825c3
feat(core): implement permission management and Full Disk Access dete…
lahiruudayakumara Aug 24, 2026
468c074
feat(core): implement file system enumeration, metadata, and access m…
lahiruudayakumara Aug 24, 2026
1118485
feat(core): implement storage analysis, disk metrics, and directory s…
lahiruudayakumara Aug 24, 2026
0ffe870
feat(core): implement scanning engine, coordinators, models, and spec…
lahiruudayakumara Aug 24, 2026
92b27db
feat(core): implement cleanup engine, deletion service, and Trash rel…
lahiruudayakumara Aug 24, 2026
5da0111
feat(config): add App Info.plist, Localizable resources, and privacy …
lahiruudayakumara Aug 25, 2026
df4348b
feat(ui): add navigation coordinator, theme modifiers, and core UI co…
lahiruudayakumara Aug 25, 2026
9e0082f
feat(dashboard): implement redesigned dashboard overview and status c…
lahiruudayakumara Aug 25, 2026
120431e
feat(features): implement SmartScan, StorageAnalyzer, Duplicates, Lar…
lahiruudayakumara Aug 25, 2026
62fc14e
feat(features): implement StartupItems, Uninstaller, Privacy, Setting…
lahiruudayakumara Aug 25, 2026
7a73bee
feat(app): wire up ContentView navigation split view and AppEnvironme…
lahiruudayakumara Aug 25, 2026
9ec78ae
chore(ci): add build scripts, packaging configurations, workflows, an…
lahiruudayakumara Aug 25, 2026
20d9b4d
feat(models-services): add domain data models and feature services
lahiruudayakumara Aug 25, 2026
74953fd
docs(architecture): update distribution model and system architecture…
lahiruudayakumara Aug 25, 2026
27e3a03
Merge branch 'main' into dev
lahiruudayakumara Aug 25, 2026
65558cd
feat(assets): add 1:1 metallic geometric 'M' app icon logo
lahiruudayakumara Aug 25, 2026
4347682
docs(readme): fix logo image path and remove emojis
lahiruudayakumara Aug 25, 2026
c256995
docs(repo): update repository URLs to opencorex-org/macsweep
lahiruudayakumara Aug 25, 2026
cb8b602
feat(assets): add standalone isolated PNG logo without background con…
lahiruudayakumara Aug 25, 2026
bafd99d
fix(assets): replace faux checkerboard with true transparent RGBA PNG…
lahiruudayakumara Aug 25, 2026
481ea5e
fix(assets): update macOS AppIcon set to use true transparent RGBA PN…
lahiruudayakumara Aug 25, 2026
dc406b0
Merge branch 'main' into dev
lahiruudayakumara Aug 25, 2026
e63f5bd
feat: add FUNDING.yml to support project sponsorship
lahiruudayakumara Aug 25, 2026
c4eceb8
fix(dashboard): use valid SF Symbol checkmark.shield.fill
lahiruudayakumara Aug 25, 2026
9ae88ac
fix(project): update objectVersion to 56 for Xcode 15.4 and CI compat…
lahiruudayakumara Aug 25, 2026
5d18626
feat(scanner): expand scanning paths and implement real-time progress…
lahiruudayakumara Aug 25, 2026
78866ba
feat(smartscan): enhance progress UI, selection controls, approval fl…
lahiruudayakumara Aug 25, 2026
5fb4c1a
ci: select Xcode 16 in workflows to support Synchronized Groups
lahiruudayakumara Aug 25, 2026
8402b4c
fix(project): restore objectVersion 77 for Xcode 16 Synchronized Groups
lahiruudayakumara Aug 25, 2026
bcc3964
ci: use setup-xcode action to dynamically select Xcode 16 on GitHub A…
lahiruudayakumara Aug 25, 2026
ec9d19d
Add review and approval flows to cleaners
lahiruudayakumara Aug 30, 2026
ab22c64
feat: implement language selection support and app localization manag…
lahiruudayakumara Aug 30, 2026
0f4987d
fix(merge): resolve conflicts between dev and main
lahiruudayakumara Aug 30, 2026
f255f2c
feat: add granular scan progress, disable app sandbox, update file di…
lahiruudayakumara Aug 30, 2026
e1099c0
chore: update localized strings for consistency
lahiruudayakumara Aug 30, 2026
0272946
Improve app uninstaller flow
lahiruudayakumara Aug 30, 2026
283f8ea
chore: update localization strings for consistency across the applica…
lahiruudayakumara Aug 30, 2026
0d75b5f
Merge branch 'main' into dev
lahiruudayakumara Aug 30, 2026
097578b
Fix uninstaller permission handling
lahiruudayakumara Aug 30, 2026
da755a1
Replace unstable AppKit progress controls
lahiruudayakumara Aug 30, 2026
3e4eed3
Redesign settings screens
lahiruudayakumara Aug 30, 2026
d8d062a
chore: update localization strings and reformat README title alignment
lahiruudayakumara Aug 30, 2026
a861994
fix(merge): resolve conflicts between dev and main for PR #11
lahiruudayakumara Aug 30, 2026
062d05e
refactor: remove ApplicationUninstallProgressView and ApplicationUnin…
lahiruudayakumara Aug 30, 2026
dfaf323
Fix Xcode 16 actor callback build
lahiruudayakumara Aug 30, 2026
8fd1b3f
Add developer storage management prototype
lahiruudayakumara Aug 30, 2026
484a5e9
feat(cleaner): support direct permanent deletion for approved items a…
lahiruudayakumara Sep 6, 2026
69f917c
feat(scanner): introduce ScanControl for pause/resume/cancel and inte…
lahiruudayakumara Sep 6, 2026
695e9ca
feat(smartscan): add pause, resume, and cancellation controls to Smar…
lahiruudayakumara Sep 6, 2026
ba3b6b2
feat(fullscan): add dedicated Full Scan feature and connect dashboard…
lahiruudayakumara Sep 6, 2026
63709ab
feat(developer-cleaner): revamp UI with scan controls, risk-aware def…
lahiruudayakumara Sep 6, 2026
fed64a0
chore(i18n): update localizable catalog for scan controls and redesig…
lahiruudayakumara Sep 6, 2026
1658e20
Merge branch 'main' into dev
lahiruudayakumara Sep 6, 2026
34a1448
feat(updates): integrate Sparkle framework for secure in-app updates …
lahiruudayakumara Sep 6, 2026
e48ca78
feat(ci): configure CI and verification workflows for macOS 15 and la…
lahiruudayakumara Sep 6, 2026
cc789f1
feat(release): add Developer ID export, signing, notarization, and pa…
lahiruudayakumara Sep 6, 2026
4c5ed14
docs: document release procedure, v1.0.0 release notes, and update ch…
lahiruudayakumara Sep 6, 2026
d010aaf
feat: integrate Sparkle framework and add update settings to AppEnvir…
lahiruudayakumara Sep 7, 2026
e4c7ed7
Merge branch 'main' into dev
lahiruudayakumara Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ on:

jobs:
build:
runs-on: macos-14
runs-on: macos-15
steps:
- uses: actions/checkout@v7
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16'
xcode-version: latest-stable
- name: Build MacSweep
run: xcodebuild -project MacSweep.xcodeproj -scheme MacSweep -destination 'platform=macOS' CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO build

run: ./scripts/build.sh

101 changes: 94 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,104 @@ name: Release
on:
push:
tags:
- 'v*'
- 'v[0-9]+.[0-9]+.[0-9]+'

permissions:
contents: write

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
runs-on: macos-14
runs-on: macos-15
timeout-minutes: 60
env:
RELEASE_VERSION: ${{ github.ref_name }}
DEVELOPMENT_TEAM: HT7R9CG7ZN
GH_TOKEN: ${{ github.token }}
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }}
APPLE_API_PRIVATE_KEY: ${{ secrets.APPLE_API_PRIVATE_KEY }}
SPARKLE_PUBLIC_KEY: ${{ secrets.SPARKLE_PUBLIC_KEY }}
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}

steps:
- uses: actions/checkout@v7
- uses: maxim-lobanov/setup-xcode@v1
- name: Check out tagged source
uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Select Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16'
- name: Build & Package
run: ./scripts/release.sh
xcode-version: latest-stable

- name: Validate release credentials
shell: bash
run: |
set -euo pipefail
for name in MACOS_CERTIFICATE MACOS_CERTIFICATE_PASSWORD KEYCHAIN_PASSWORD APPLE_API_KEY_ID APPLE_API_ISSUER_ID APPLE_API_PRIVATE_KEY SPARKLE_PUBLIC_KEY SPARKLE_PRIVATE_KEY; do
if [[ -z "${!name:-}" ]]; then
echo "Required GitHub secret is missing: $name" >&2
exit 1
fi
done

- name: Import Developer ID certificate
shell: bash
run: |
set -euo pipefail
CERTIFICATE_PATH="$RUNNER_TEMP/developer-id.p12"
KEYCHAIN_PATH="$RUNNER_TEMP/macsweep-signing.keychain-db"
printf '%s' "$MACOS_CERTIFICATE" | base64 --decode > "$CERTIFICATE_PATH"
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security import "$CERTIFICATE_PATH" -P "$MACOS_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security list-keychains -d user -s "$KEYCHAIN_PATH"

- name: Prepare App Store Connect API key
shell: bash
run: |
set -euo pipefail
API_KEY_PATH="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8"
printf '%s' "$APPLE_API_PRIVATE_KEY" > "$API_KEY_PATH"
chmod 600 "$API_KEY_PATH"
echo "APPLE_API_KEY_PATH=$API_KEY_PATH" >> "$GITHUB_ENV"

- name: Resolve dependencies
run: xcodebuild -resolvePackageDependencies -project MacSweep.xcodeproj -scheme MacSweep -clonedSourcePackagesDirPath build/SourcePackages

- name: Build, sign, notarize, and package
shell: bash
run: |
set -euo pipefail
export RELEASE_VERSION="${RELEASE_VERSION#v}"
./scripts/release.sh

- name: Publish GitHub Release
shell: bash
run: |
set -euo pipefail
VERSION="${RELEASE_VERSION#v}"
gh release create "$RELEASE_VERSION" \
"build/Release/MacSweep-$VERSION.dmg" \
"build/Release/MacSweep-$VERSION.zip" \
"build/Release/appcast.xml" \
"build/Release/SHA256SUMS.txt" \
--verify-tag \
--title "MacSweep $RELEASE_VERSION" \
--notes-file RELEASE_NOTES.md

- name: Remove temporary signing material
if: always()
shell: bash
run: |
security delete-keychain "$RUNNER_TEMP/macsweep-signing.keychain-db" 2>/dev/null || true
rm -f "$RUNNER_TEMP/developer-id.p12" "$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8"
19 changes: 9 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
name: Test
name: Verify

on:
push:
branches: [ main ]
branches: [main, dev]
pull_request:
branches: [ main ]
branches: [main]

jobs:
test:
runs-on: macos-14
verify:
runs-on: macos-15
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16'
- name: Run Tests
run: xcodebuild -project MacSweep.xcodeproj -scheme MacSweep -destination 'platform=macOS' CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO test || true


xcode-version: latest-stable
- name: Build and analyze
run: ./scripts/test.sh
35 changes: 13 additions & 22 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
# Changelog

All notable changes to **MacSweep** will be documented in this file.
All notable changes to MacSweep are documented here.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 2026-09-06

---
### Added

## [Unreleased]
- Smart Scan, Full Scan, and Developer Cleaner workflows.
- Pause, Resume, and Stop controls for active scans.
- Secure Sparkle-based automatic update support.
- Developer ID signing, Apple notarization, DMG packaging, checksums, and GitHub Release automation.

### Planned
- Storage Analyzer interactive tree component (`v0.2.0`)
- Large File Finder threshold scanning (`v0.2.0`)
- Duplicate File Detection engine (`v0.3.0`)
- Application Uninstaller leftover finder (`v0.4.0`)
### Changed

---
- Cleanup permanently removes safety-approved items after explicit confirmation.
- Large File cleanup and App Uninstaller continue to use the macOS Trash for recoverability.

## [0.1.0-beta] - 2026-08-24
### Security

### Added
- Initial OpenCorex project structure and Xcode workspace layout.
- Decoupled `Scanner`, `Cleaner`, and `Safety` engine architecture.
- Core safety rules database (`ProtectedPaths.swift`) enforcing zero system file deletion.
- Native macOS `FileManager.trashItem` implementation.
- Developer cache scanners for Xcode DerivedData, Gradle, Node/npm, Homebrew, and Docker.
- Unified SwiftUI `DashboardView`, `SmartScanView`, and `SettingsView`.
- Build, test, notarization, and DMG packaging automation scripts (`scripts/`).
- GitHub Actions CI/CD workflows (`ci.yml`, `test.yml`, `release.yml`).
- Comprehensive technical documentation (`docs/architecture.md`, `docs/permissions.md`, `docs/development.md`, `docs/releases.md`, `docs/privacy.md`).
- Update archives require an EdDSA signature and Developer ID validation.
- Release publication fails if signing, notarization, verification, or packaging fails.
6 changes: 5 additions & 1 deletion Distribution/ExportOptions/DeveloperIDExportOptions.plist
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
<key>method</key>
<string>developer-id</string>
<key>signingStyle</key>
<string>automatic</string>
<string>manual</string>
<key>signingCertificate</key>
<string>Developer ID Application</string>
<key>teamID</key>
<string>HT7R9CG7ZN</string>
</dict>
</plist>
42 changes: 40 additions & 2 deletions MacSweep.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
objectVersion = 77;
objects = {

/* Begin PBXBuildFile section */
A10000000000000000000001 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = A10000000000000000000002 /* Sparkle */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
E09477E2303BE110000677B9 /* MacSweep.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacSweep.app; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
Expand All @@ -23,6 +27,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A10000000000000000000001 /* Sparkle in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -65,6 +70,7 @@
);
name = MacSweep;
packageProductDependencies = (
A10000000000000000000002 /* Sparkle */,
);
productName = MacSweep;
productReference = E09477E2303BE110000677B9 /* MacSweep.app */;
Expand Down Expand Up @@ -96,6 +102,9 @@
minimizedProjectReferenceProxies = 1;
preferredProjectObjectVersion = 77;
productRefGroup = E09477E3303BE110000677B9 /* Products */;
packageReferences = (
A10000000000000000000003 /* XCRemoteSwiftPackageReference "Sparkle" */,
);
projectDirPath = "";
projectRoot = "";
targets = (
Expand Down Expand Up @@ -260,11 +269,16 @@
ENABLE_USER_SELECTED_FILES = readonly;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_SUAllowsAutomaticUpdates = YES;
INFOPLIST_KEY_SUAutomaticallyUpdate = NO;
INFOPLIST_KEY_SUEnableAutomaticChecks = YES;
INFOPLIST_KEY_SUFeedURL = "https://github.com/opencorex-org/macsweep/releases/latest/download/appcast.xml";
INFOPLIST_KEY_SUPublicEDKey = "$(SPARKLE_PUBLIC_KEY)";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = org.opencorex.MacSweep;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand Down Expand Up @@ -292,11 +306,16 @@
ENABLE_USER_SELECTED_FILES = readonly;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INFOPLIST_KEY_SUAllowsAutomaticUpdates = YES;
INFOPLIST_KEY_SUAutomaticallyUpdate = NO;
INFOPLIST_KEY_SUEnableAutomaticChecks = YES;
INFOPLIST_KEY_SUFeedURL = "https://github.com/opencorex-org/macsweep/releases/latest/download/appcast.xml";
INFOPLIST_KEY_SUPublicEDKey = "$(SPARKLE_PUBLIC_KEY)";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = org.opencorex.MacSweep;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand Down Expand Up @@ -331,6 +350,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
A10000000000000000000003 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/sparkle-project/Sparkle";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.9.4;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
A10000000000000000000002 /* Sparkle */ = {
isa = XCSwiftPackageProductDependency;
package = A10000000000000000000003 /* XCRemoteSwiftPackageReference "Sparkle" */;
productName = Sparkle;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = E09477DA303BE110000677B9 /* Project object */;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions MacSweep/App/AppEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public final class AppEnvironment: ObservableObject {
// MARK: - Feature Services
public let largeFileService: LargeFileService
public let applicationService: ApplicationService
public let updateService: UpdateService

public init() {
self.diskSpaceService = DiskSpaceService()
Expand All @@ -29,5 +30,6 @@ public final class AppEnvironment: ObservableObject {
self.cleanEngine = CleanEngine(safetyValidator: safetyValidator)
self.largeFileService = LargeFileService()
self.applicationService = ApplicationService()
self.updateService = UpdateService()
}
}
36 changes: 35 additions & 1 deletion MacSweep/Features/Settings/Sections/GeneralSettings.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import SwiftUI

public struct GeneralSettings: View {
@EnvironmentObject private var environment: AppEnvironment
@ObservedObject var viewModel: SettingsViewModel
@State private var showRestartAlert = false
@State private var pendingLanguage: AppLanguage? = nil
Expand Down Expand Up @@ -37,8 +38,41 @@ public struct GeneralSettings: View {
title: "Automatic update checks",
detail: "Check for new MacSweep versions in the background",
icon: "arrow.down.circle",
isOn: $viewModel.autoCheckUpdates
isOn: Binding<Bool>(
get: { environment.updateService.automaticallyChecksForUpdates },
set: { environment.updateService.automaticallyChecksForUpdates = $0 }
)
)

Divider().padding(.leading, 33)

SettingsToggleRow(
title: "Automatically download updates",
detail: "Securely download verified updates and install them when MacSweep quits",
icon: "arrow.down.app",
isOn: Binding<Bool>(
get: { environment.updateService.automaticallyDownloadsUpdates },
set: { environment.updateService.automaticallyDownloadsUpdates = $0 }
)
)

Divider().padding(.leading, 33)

HStack {
VStack(alignment: .leading, spacing: 3) {
Text("Check manually")
.font(.system(size: 12, weight: .medium))
Text("Look for a new signed release now")
.font(.system(size: 10))
.foregroundColor(.msSecondaryLabel)
}
Spacer()
Button("Check Now") {
environment.updateService.checkForUpdates()
}
.buttonStyle(.bordered)
.disabled(!environment.updateService.isConfigured)
}
}
}

Expand Down
Loading