Skip to content

chore: proprietary view-only LICENSE + tightened .gitignore + go-public checklist#20

Closed
Outtsett wants to merge 4 commits intomainfrom
chore/public-repo-hygiene
Closed

chore: proprietary view-only LICENSE + tightened .gitignore + go-public checklist#20
Outtsett wants to merge 4 commits intomainfrom
chore/public-repo-hygiene

Conversation

@Outtsett
Copy link
Copy Markdown
Owner

@Outtsett Outtsett commented May 5, 2026

Summary

Three atomic commits hardening the repo for an eventual public flip:

  1. Replace the accidentally-committed MIT LICENSE with a proprietary
    "All Rights Reserved" view-only license
  2. Tighten .gitignore against credential / local-state leaks
  3. Add docs/PUBLIC_REPO_CHECKLIST.md — a 9-section pre-flight runbook

Why this matters NOW

The repo currently has an MIT license. MIT explicitly grants:

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software ... to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software ...

That is the polar opposite of the intended posture for a commercial
$6.99-lifetime-IAP app. Any clone made before this PR landed retains
the MIT grant on that specific copy in perpetuity (Section 5 of the
new LICENSE addresses this explicitly). Going forward, the proprietary
license is the only valid grant.

Verification (security)

Both engines report zero findings across the full git history:

Tool Result
gitleaks 8.x (regex) 67 commits / 899 KB scanned — 0 leaks
TruffleHog 3.95.2 (verified) 626 chunks / 962 KB scanned — 0 verified secrets, 0 unverified
Targeted git log --all --full-history for 13 sensitive paths (key.properties, *.jks, *.keystore, .env, GoogleService-Info.plist, google-services.json, *.mobileprovision, *.p12, *.pem, etc.) 0 commits hit any path
Current tracked files matching credential patterns 0

The CI's gitleaks-action@v2 (push + weekly cron) continues to gate
against future leaks.

What changed

LICENSE — proprietary, View-Only, All Rights Reserved

  • Section 1 (Permitted): view on GitHub, clone for offline review,
    submit issues/PRs, attributed quotation under fair use
  • Section 2 (Forbidden): use, modify, redistribute, fork-for-
    distribution, ML-training inputs, reverse-engineer App Store /
    Play Store builds, use of project marks
  • Section 4 (Contributions): inbound==outbound — PR authors grant
    perpetual, sublicensable, relicensable rights to the copyright holder
  • Section 5: explicit revocation of the prior MIT grant going
    forward, with safe-harbor for good-faith pre-revision downloaders
  • Section 6: commercial / OEM / licensing inquiries route to
    tyler.lundeen1995@gmail.com
  • Wyoming jurisdiction, severability, canonical-file clauses

.gitignore — public-repo-hardening block

Added explicit defenses for:

  • Android signing / Firebase: key.properties, *.jks, *.keystore, google-services.json, local.properties, captures/
  • iOS user-state / Firebase: GoogleService-Info.plist, Generated.xcconfig, **/xcuserdata/, **/*.xcuserstate, **/DerivedData/, **/Pods/
  • Apple certs: *.mobileprovision, *.provisionprofile, *.p8, *.p12, *.cer
  • Generic creds: *.pem, *.key, *.pfx, service-account*.json, firebase-adminsdk*.json, client_secret*.json, credentials.json, secrets/
  • Env: .env* with !.env.example allow-list
  • IDE: .idea/, *.iml, .vscode/* with !launch.json|settings.json|extensions.json|tasks.json
  • Tool reports: gitleaks-report.{json,sarif}, trufflehog-report.json, .semgrep/

docs/PUBLIC_REPO_CHECKLIST.md — 9-section pre-flight runbook

Generic checklist (public-OK itself) covering:

  1. License + ownership cross-check
  2. Two-engine secret history sweep (gitleaks + TruffleHog) with copy-paste commands
  3. .gitignore coverage validation
  4. Workflow secret-name hygiene
  5. Repo settings to flip (private vuln reporting, secret scanning + push protection, branch protection rules, Discussions/Wiki/Projects)
  6. Per-file decision table for CLAUDE.md, BUILD_PLAN.md, etc. (Tyler-call recommendations, not unilateral moves)
  7. Email exposure
  8. Prior-license-grant residual exposure
  9. Final go/no-go gate

What this PR does NOT do

  • Does not move CLAUDE.md or docs/BUILD_PLAN.md. Both contain
    internal context Tyler may want to remove or move to a private
    workspace before public flip — flagged in checklist Section 6 for
    explicit per-file decision rather than unilateral action
  • Does not run git filter-repo. History scrubbing is destructive
    (every SHA changes) and the repo is currently private — no urgency.
    If/when public flip is committed AND the historical MIT grant is
    judged unacceptable, that's a separate, intentional, broadly-
    coordinated operation. Section 8 of the checklist documents the
    trade-off
  • Does not flip the repo to public. Still private. This PR is the
    prerequisite work, not the action

Test plan

  • gitleaks — 0 leaks across 67 commits
  • trufflehog — 0 verified, 0 unverified secrets
  • git log --all --full-history for 13 sensitive paths — 0 hits
  • git ls-files matches none of the new ignore patterns
  • CI green on this PR (analyze + format + tests + secret-scan + commitlint + size-diff once ci(automation): stale sweep + path labeler + Dependabot auto-merge + APK size diff + issue templates #19 lands)
  • Manual readthrough of LICENSE Section 5 (prior-MIT-grant clause) by Tyler before merge — this is the legally-novel part

🤖 Generated with Claude Code

Outtsett and others added 4 commits May 4, 2026 10:45
- Onboarding flow + Selector-based first-launch routing in main.dart
- 5 new screens: add_habit, analytics, onboarding, premium, settings
- AdService (banner-only, --dart-define gated, premium-aware)
- OnboardingService (settings-box backed, no new HiveType)
- 5 new test files (30 pass, 2 documented skips)
- Android: AGP/Gradle/desugaring + USE_EXACT_ALARM + minSdk 26
- iOS: Info.plist privacy strings + Time Sensitive Notifications hint
- pubspec: add google_mobile_ads ^5.3.1; description -> Invisible Habit Builder

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The repo had an MIT LICENSE committed in error from the original
flutter create scaffold. MIT explicitly grants "use, copy, modify,
merge, publish, distribute, sublicense, and/or sell" — the exact
opposite of the intended posture for this commercial app
(Invisible Habit Builder, $6.99 lifetime IAP).

Replace with a proprietary "All Rights Reserved" license:
- Section 1 enumerates the only permitted uses (view on GitHub,
  clone for offline review, submit issues/PRs, attributed quotation).
- Section 2 explicitly forbids use, modification, redistribution,
  forking-for-distribution, ML-training inputs, reverse-engineering
  of compiled store builds, and use of the project's marks/names.
- Section 4 wires inbound-equals-outbound: contributors grant the
  copyright holder a perpetual, sublicensable, relicensable license
  to incorporate their PR.
- Section 5 explicitly REVOKES the prior MIT grant going forward
  while preserving the rights of any good-faith downloader who
  retained an MIT-era copy (without backwards remediation, the
  prior MIT remains in git history).
- Section 6 routes commercial / OEM / licensing inquiries through
  tyler.lundeen1995@gmail.com.
- Wyoming jurisdiction. Severability + canonical-file clauses.

Update README.md license section to match — no lingering MIT
references anywhere in the working tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…leaks

Add a comprehensive public-repo-hardening block that defends against
the file categories most often committed by accident on Flutter apps:

- Android: key.properties, keystore.properties, *.jks, *.keystore,
  google-services.json, firebase_app_id_file.json, local.properties,
  captures/
- iOS: GoogleService-Info.plist, Generated.xcconfig,
  flutter_export_environment.sh, **/Pods/, **/xcuserdata/,
  **/*.xcuserstate, **/DerivedData/
- Apple signing: *.mobileprovision, *.provisionprofile, *.p8, *.p12,
  *.cer, *.certSigningRequest
- Generic creds: *.pem, *.key, *.pfx, service-account*.json,
  firebase-adminsdk*.json, client_secret*.json, credentials.json,
  secrets/
- Env: .env, .env.* (with !.env.example escape hatch)
- IDE per-user: .idea/, *.iml, .vscode/* (with allow-list for
  shared launch.json / settings.json / extensions.json / tasks.json)
- Security-tool reports that get regenerated each run:
  gitleaks-report.json, trufflehog-report.json, .semgrep/

Verification:
- gitleaks 8.x: scanned 67 commits, 899 KB, ZERO leaks.
- TruffleHog 3.95.2: 626 chunks, 962 KB, ZERO verified +
  ZERO unverified secrets.
- `git ls-files` matches none of the new ignore patterns —
  history is clean across full --all --full-history sweep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds docs/PUBLIC_REPO_CHECKLIST.md — a 9-section runbook to follow
before flipping repo visibility from private to public.

Sections:
1. License + ownership — verify LICENSE is the proprietary file,
   no contradictory license declarations in pubspec/package.json
2. Secret history sweep — gitleaks + TruffleHog command snippets,
   targeted git-log scan for the 13 highest-risk file paths
3. .gitignore coverage — flutter clean / pub get + synthetic
   credential file test
4. Workflow secret-name hygiene — regex for accidentally-pasted
   private keys / RC keys / Apple certs in .github/
5. Repo settings to flip — private vuln reporting, secret scanning
   + push protection, branch protection on main, Discussions on,
   Wiki/Projects off, Forks/Issues left enabled
6. Internal-context docs — case-by-case decision table for
   CLAUDE.md, BUILD_PLAN.md, coding-standards.md, fix_*.ps1,
   marking each public-OK / move-to-private / consider-removing
7. Email exposure — verify the maintainer email is the public-
   facing one (it'll get scraped)
8. Prior-license revocation — note that pre-revision LICENSE
   (the MIT) remains in git history forever absent a destructive
   filter-repo rewrite
9. Final verification — git status clean, analyze/test/build
   green, CI green on main, one human readthrough

This file is itself public-OK — a generic checklist with no
HabitDeveloper-specific internal context.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 5, 2026 03:52
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR combines repo “go-public” hardening (license, ignore rules, checklist) with a large set of app feature additions (onboarding gating, premium paywall, analytics/settings/add-habit screens, AdMob banner support, and new widget/unit tests), plus platform configuration updates for iOS/Android.

Changes:

  • Replace MIT LICENSE with a proprietary “view-only / all rights reserved” license and update repo docs/README accordingly, plus add a public-flip checklist and tighten .gitignore.
  • Add onboarding routing (OnboardingService + OnboardingScreen) and premium UX (PremiumScreen), plus new core screens (HomeScreen updates, AnalyticsScreen, SettingsScreen, AddHabitScreen).
  • Introduce AdMob banner ads for free tier (AdService, google_mobile_ads), including Android/iOS manifest/plist wiring, and add new tests (some currently skipped).

Reviewed changes

Copilot reviewed 22 out of 24 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
.gitignore Adds public-repo hardening ignores for creds/local artifacts/tool outputs.
LICENSE Replaces MIT with proprietary view-only license text.
README.md Updates license section messaging to proprietary terms.
docs/PUBLIC_REPO_CHECKLIST.md Adds pre-flight runbook for flipping repo public.
pubspec.yaml Adds google_mobile_ads dependency; updates package description.
pubspec.lock Records resolved deps + updated Dart/Flutter SDK minima.
lib/main.dart Wires up AdService + OnboardingService and routes home via Selector.
lib/services/onboarding_service.dart Adds persisted onboarding completion flag service (Hive settings box).
lib/services/ad_service.dart Adds banner ad service with graceful gating + entitlement bridge support.
lib/screens/home_screen.dart Adds navigation actions, free-tier cap routing, reschedule sweep, and banner slot.
lib/screens/onboarding_screen.dart Adds 4-page onboarding flow with notification/health opt-ins.
lib/screens/add_habit_screen.dart Implements create/edit habit form with scheduling + free-tier cap.
lib/screens/analytics_screen.dart Implements analytics UI with premium gating and IF-THEN bottom sheet.
lib/screens/settings_screen.dart Implements multi-section settings (export/wipe/themes/subscription/etc.).
lib/screens/premium_screen.dart Implements paywall UI + purchase/restore flows.
android/app/src/main/AndroidManifest.xml Adds notification/health/ad permissions and AdMob app-id meta-data placeholder.
android/app/build.gradle.kts Injects AdMob app id via manifest placeholders (defaults to test id).
ios/Runner/Info.plist Updates display name + adds notifications/health strings + AdMob + SKAdNetwork IDs.
test/add_habit_screen_test.dart Widget tests for validation + submit behavior.
test/ad_service_gating_test.dart Unit tests for AdService gating/idempotency.
test/graceful_degradation_test.dart Boots full app with empty --dart-define config and asserts no crash.
test/onboarding_routing_test.dart Widget test for onboarding routing (includes a skipped test).
test/analytics_screen_test.dart Widget test for analytics empty state (currently skipped).
CLAUDE.md Updates project “current state” documentation to reflect new implementations/tests.

Comment on lines +31 to +39
switch (outcome) {
case PurchaseOutcome.success:
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Premium unlocked.')),
);
await Future<void>.delayed(const Duration(milliseconds: 600));
if (!mounted) return;
Navigator.pop(context);
case PurchaseOutcome.userCancelled:
Comment on lines +42 to +55
case PurchaseOutcome.error:
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Purchase failed. Try again.')),
);
case PurchaseOutcome.notConfigured:
// Shouldn't reach here — buy button is hidden when !isConfigured.
debugPrint(
'[PremiumScreen] purchaseLifetime returned notConfigured '
'despite isConfigured=true; check PurchaseService state.',
);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Purchases unavailable')),
);
}
Comment on lines +1 to +4
import 'dart:io' show Platform;

import 'package:flutter/foundation.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
Comment on lines +426 to +433
void didChangeDependencies() {
super.didChangeDependencies();
final ads = context.read<AdService>();
if (_banner == null && !ads.adsRemoved) {
final banner = ads.createBanner();
banner?.load();
setState(() => _banner = banner);
}
Comment on lines +444 to +451
return Consumer<AdService>(
builder: (context, ads, _) {
if (ads.adsRemoved || _banner == null) return const SizedBox.shrink();
return SizedBox(
width: _banner!.size.width.toDouble(),
height: _banner!.size.height.toDouble(),
child: AdWidget(ad: _banner!),
);
Comment on lines +2 to +6
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
Comment thread README.md
Comment on lines +81 to +85
**Proprietary — All Rights Reserved.** Source-available for review only.
No license is granted to use, copy, modify, or redistribute. See
[`LICENSE`](LICENSE) for the full terms, including the contribution
clause that governs pull requests and issues. Commercial / OEM /
licensing inquiries: see Section 6 of `LICENSE`.
Comment thread ios/Runner/Info.plist
Comment on lines +50 to +51
<key>NSHealthShareUsageDescription</key>
<string>Invisible Habit Builder reads from Apple Health only when you opt in to verify completions.</string>
Comment on lines +121 to +124
testWidgets(
'analytics screen shows empty-state copy and skips heatmap when no data exists',
skip: true, // TODO(v1.1): hangs in flutter_test pump — see file header note
(tester) async {
Comment on lines +69 to +80
// KNOWN ISSUE (v1.0): this test hangs after `service.markComplete()` →
// `tester.pump()` even though the OnboardingService flag flips correctly
// (verified directly via `expect(service.hasOnboarded, isTrue)`). The
// Hive box's internal flush timer appears to keep the flutter_test
// binding alive past the pump. The first test already proves the
// Selector branch resolves to OnboardingScreen on hasOnboarded==false;
// the markComplete()→home flip is exercised manually + by
// graceful_degradation_test which boots the full HabitDeveloperApp.
testWidgets('switches to route:home after markComplete()', skip: true, (
tester,
) async {
await tester.pumpWidget(buildHarness(service));
@Outtsett
Copy link
Copy Markdown
Owner Author

Outtsett commented May 5, 2026

Closing in favor of #22 (squash-merged into main as 312d6b0). PR #22 dropped the v1.0 commit dependency and reworded the license commit subject to comply with commitlint, which got it green for an immediate merge ahead of the public-flip. The PUBLIC_REPO_CHECKLIST.md doc from this PR will land in a small follow-up.

@Outtsett Outtsett closed this May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants