Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
45a4f57
updates gitignore and updates version
JordanKeo45 Oct 16, 2026
dbbbf50
Merge branch 'main' into tpn-compliance
JordanKeo45 Oct 19, 2026
1d444a9
Merge branch 'main' into tpn-compliance
JordanKeo45 Oct 21, 2026
9018521
feat(links): Processing panel, clearer delete dialogs, license renewa…
JordanKeo45 Oct 22, 2026
29b5cee
feat(settings): add admin network allowlist controls
JordanKeo45 Oct 22, 2026
1539fc1
feat: add connection-aware admin network safeguards
JordanKeo45 Oct 22, 2026
50f8ca1
Fix Admin Networks HTTPS trust and button spacing
JordanKeo45 Oct 23, 2026
9d47005
feat(uploads): display malware scan progress and results
JordanKeo45 Oct 23, 2026
d8c4f21
fix(security): encrypt desktop credentials and add cross-platform hyg…
JordanKeo45 Oct 26, 2026
928dc97
update qa test runner for mac
JordanKeo45 Oct 26, 2026
f3bf934
update hygene qa file
JordanKeo45 Oct 26, 2026
c0d5bb0
fix(security): harden webviews and remote server setup
JordanKeo45 Oct 26, 2026
ac877d3
fix: polish link titles, expired-license UI, and Quick Share logout c…
JordanKeo45 Oct 27, 2026
2bcf36e
fix: require reconnect when switching to a logged-out server
JordanKeo45 Oct 27, 2026
0e83b1f
fixes user guide and readme
JordanKeo45 Oct 28, 2026
5d664fc
fixes electron bundle including unneccesary files
JordanKeo45 Oct 28, 2026
5993c5d
Bump version to 1.0.8
JordanKeo45 Oct 28, 2026
8019b60
Fix CodeQL alerts in hygiene harness and tests
JordanKeo45 Oct 28, 2026
85957ba
ci: add security checks, Semgrep CE scanning, and Dependabot
JordanKeo45 Oct 28, 2026
56c285f
ci: fix yarn install mode; set GCM auth tag length in test mock
JordanKeo45 Oct 28, 2026
f02b689
fix(deps): clear audit advisories; time-boxed Electron exception
JordanKeo45 Oct 28, 2026
3939b31
fix(security): mitigate Electron 38 advisories without upgrading
JordanKeo45 Oct 28, 2026
c7a1b1a
test(security): add yarn test:hardening Electron QA harness
JordanKeo45 Oct 28, 2026
52adeec
adds local ai security audit script + workflow
JordanKeo45 Oct 28, 2026
7eac713
test(security): use exact match for externally opened URLs in harness
JordanKeo45 Oct 28, 2026
3b39231
Bump version to 1.0.9
JordanKeo45 Oct 28, 2026
349176c
Fix macOS universal packaging for FFmpeg and FFprobe binaries
JordanKeo45 Oct 28, 2026
4fd8f11
fixes confirmation modal stacking issues
JordanKeo45 Oct 29, 2026
44556ba
feat(comments): add premium moderator delete for link comments
JordanKeo45 Oct 29, 2026
3118999
feat(quickshare): validate batches before uploading
JordanKeo45 Oct 29, 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
29 changes: 29 additions & 0 deletions .github/audit-exceptions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"exceptions": [
{
"package": "electron",
"reason": "Electron 38 is end-of-life; clearing these requires a major runtime upgrade with cross-platform QA, tracked as a separate task.",
"expires": "2027-01-31",
"advisories": [
{ "id": 1116060, "ghsa": "GHSA-532v-xpq5-8h95" },
{ "id": 1136552, "ghsa": "GHSA-v3j7-r9gq-3gjw" },
{ "id": 1136567, "ghsa": "GHSA-h7rp-cf8h-j98x" },
{ "id": 1136607, "ghsa": "GHSA-9f4c-93c8-jc8g" },
{ "id": 1239973, "ghsa": "GHSA-hq2x-r82h-9wj4" },
{ "id": 1239977, "ghsa": "GHSA-gr2m-v5gq-v685" },
{ "id": 1239981, "ghsa": "GHSA-j84w-jfhq-vhvj" },
{ "id": 1241657, "ghsa": "GHSA-9qh4-3jw8-366w" },
{ "id": 1243069, "ghsa": "GHSA-jr5w-w6x2-84p9" }
]
},
{
"package": "extract-zip",
"reason": "No patched release exists; pulled in only by the electron 38 package installer and removed by the Electron upgrade (42.11.16+ no longer depends on it).",
"expires": "2027-01-31",
"advisories": [
{ "id": 1139346, "ghsa": "GHSA-jmr9-qjv8-65gv" },
{ "id": 1193685, "ghsa": "GHSA-7pqw-9j4j-h8q3" }
]
}
]
}
27 changes: 27 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
groups:
minor-and-patch:
patterns:
- '*'
update-types:
- minor
- patch
open-pull-requests-limit: 10

- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
groups:
minor-and-patch:
patterns:
- '*'
update-types:
- minor
- patch
open-pull-requests-limit: 10
977 changes: 977 additions & 0 deletions .github/scripts/ai_security_audit.py

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions .github/scripts/audit.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env node
// Runs the Yarn audit, ignoring only unexpired advisories listed in .github/audit-exceptions.json.
import { readFileSync } from 'node:fs'
import { spawnSync } from 'node:child_process'

const file = new URL('../audit-exceptions.json', import.meta.url)
const { exceptions = [] } = JSON.parse(readFileSync(file, 'utf8'))
const today = new Date().toISOString().slice(0, 10)
const ignores = []
let invalid = false

for (const entry of exceptions) {
if (!/^\d{4}-\d{2}-\d{2}$/.test(entry.expires ?? '') || !entry.reason || !entry.advisories?.length) {
console.error(`::error::Audit exception for ${entry.package} needs a reason, advisories and an expires date (YYYY-MM-DD).`)
invalid = true
} else if (today > entry.expires) {
console.error(`::error::Audit exception for ${entry.package} expired on ${entry.expires}. Fix the advisories or renew the exception.`)
invalid = true
} else {
console.log(`Ignoring ${entry.advisories.length} ${entry.package} advisories until ${entry.expires}: ${entry.reason}`)
for (const { id } of entry.advisories) ignores.push('--ignore', String(id))
}
}
if (invalid) process.exit(1)

const result = spawnSync('yarn', ['npm', 'audit', '--all', '--recursive', '--severity', 'high', ...ignores], {
stdio: 'inherit',
shell: process.platform === 'win32',
})
process.exit(result.status ?? 1)
93 changes: 93 additions & 0 deletions .github/workflows/ai-security-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: AI security audit

on:
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review, edited]

permissions:
contents: read

jobs:
audit:
name: AI security audit
# Title/description edits do not change the code; only a base-branch change does.
if: ${{ github.event.action != 'edited' || github.event.changes.base != null }}
# Job-level so a skipped edit event cannot cancel an in-progress audit.
concurrency:
group: ai-security-audit-${{ github.event.pull_request.number }}
cancel-in-progress: true
runs-on: ${{ vars.AI_SECURITY_RUNNER || 'buildinator-group' }}
# Large PRs are audited as several sequential model requests, each of
# which may take up to AI_SECURITY_REQUEST_TIMEOUT (default 15 minutes).
timeout-minutes: 120
permissions:
contents: read
pull-requests: write
statuses: write
steps:
# Never check out or execute the PR head under pull_request_target.
# github.sha is the base branch tip when the event fired; the PR's
# base.sha can be stale and would run outdated audit tooling.
- name: Check out trusted audit tooling
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false
submodules: false
clean: true

- name: Mark PR head audit pending
env:
GITHUB_TOKEN: ${{ github.token }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: python3 -I .github/scripts/ai_security_audit.py pending

- name: Fetch PR objects without checking them out
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
AUTH="$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 -w0)"
echo "::add-mask::$AUTH"
git -c "http.extraheader=AUTHORIZATION: basic $AUTH" fetch --no-tags origin \
"+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/ai-audit-head"
test "$(git rev-parse refs/remotes/origin/ai-audit-head)" = "$HEAD_SHA"

- name: Audit changed code with local LiteLLM
env:
LITELLM_BASE_URL: ${{ secrets.LITELLM_BASE_URL }}
LITELLM_API_KEY: ${{ secrets.LITELLM_API_KEY }}
LITELLM_MODEL: ${{ vars.LITELLM_MODEL }}
LITELLM_SEED: ${{ vars.LITELLM_SEED }}
AI_SECURITY_CONTEXT_BYTES: ${{ vars.AI_SECURITY_CONTEXT_BYTES || '60000' }}
AI_SECURITY_BATCH_BYTES: ${{ vars.AI_SECURITY_BATCH_BYTES }}
AI_SECURITY_MAX_BATCHES: ${{ vars.AI_SECURITY_MAX_BATCHES }}
AI_SECURITY_MAX_TOKENS: ${{ vars.AI_SECURITY_MAX_TOKENS }}
AI_SECURITY_REQUEST_TIMEOUT: ${{ vars.AI_SECURITY_REQUEST_TIMEOUT }}
AI_SECURITY_MIN_BLOCKING_CONFIDENCE: ${{ vars.AI_SECURITY_MIN_BLOCKING_CONFIDENCE }}
AI_SECURITY_MAX_VERIFICATIONS: ${{ vars.AI_SECURITY_MAX_VERIFICATIONS }}
AI_SECURITY_VERIFY_CONTEXT_BYTES: ${{ vars.AI_SECURITY_VERIFY_CONTEXT_BYTES }}
AI_SECURITY_FAIL_ON: ${{ vars.AI_SECURITY_FAIL_ON || 'high' }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
# -I also prevents Python imports from the workspace/PYTHONPATH.
run: python3 -I .github/scripts/ai_security_audit.py audit

- name: Publish job summary and PR comment
if: ${{ always() && !cancelled() }}
env:
GITHUB_TOKEN: ${{ github.token }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: python3 -I .github/scripts/ai_security_audit.py report

- name: Upload audit reports
if: ${{ always() && !cancelled() }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ai-security-audit-${{ github.event.pull_request.number }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/ai-security-audit-${{ github.run_id }}-${{ github.run_attempt }}/
if-no-files-found: error
retention-days: 14
73 changes: 73 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Security checks

on:
pull_request:
push:
branches:
- main
- build
workflow_dispatch:

permissions:
contents: read

jobs:
dependency-audit:
name: Dependency audit
runs-on: ubuntu-latest
steps:
- name: Check out repository and submodules
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: recursive

- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22

- name: Install dependencies without running build scripts
run: |
corepack enable
yarn install --immutable --mode=skip-build

- name: Fail on high or critical dependency advisories
run: node .github/scripts/audit.mjs

secret-scan:
name: Secret scan
runs-on: ubuntu-latest
steps:
- name: Check out full history
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
submodules: recursive

- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: '1.24.x'

- name: Install Gitleaks
run: |
go install github.com/zricethezav/gitleaks/v8@v8.30.1
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"

- name: Scan changes or full history
env:
EVENT_NAME: ${{ github.event_name }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PUSH_BEFORE_SHA: ${{ github.event.before }}
PUSH_AFTER_SHA: ${{ github.sha }}
run: |
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
gitleaks git --redact --verbose --log-opts=--all
elif [[ "$EVENT_NAME" == "pull_request" ]]; then
gitleaks git --redact --verbose --log-opts="${PR_BASE_SHA}..${PR_HEAD_SHA}"
elif [[ "$PUSH_BEFORE_SHA" =~ ^0+$ ]]; then
gitleaks git --redact --verbose --log-opts="$PUSH_AFTER_SHA"
else
gitleaks git --redact --verbose --log-opts="${PUSH_BEFORE_SHA}..${PUSH_AFTER_SHA}"
fi
69 changes: 69 additions & 0 deletions .github/workflows/semgrep.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Semgrep CE

on:
pull_request:
push:
branches:
- main
- build
workflow_dispatch:

permissions:
contents: read

jobs:
semgrep:
name: Semgrep CE (report-only)
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Check out repository and submodules
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: recursive

- name: Install pinned Semgrep CE
run: |
python3 -m venv "$RUNNER_TEMP/semgrep-venv"
"$RUNNER_TEMP/semgrep-venv/bin/python" -m pip install --disable-pip-version-check semgrep==1.182.0

- name: Fetch pinned Semgrep Express rules
run: |
git init "$RUNNER_TEMP/semgrep-rules"
git -C "$RUNNER_TEMP/semgrep-rules" remote add origin https://github.com/semgrep/semgrep-rules.git
git -C "$RUNNER_TEMP/semgrep-rules" sparse-checkout init --cone
git -C "$RUNNER_TEMP/semgrep-rules" sparse-checkout set javascript/express/security
git -C "$RUNNER_TEMP/semgrep-rules" fetch --depth 1 --filter=blob:none origin 16b9e6d45f10649f6a531ec4838ed9924372c3bc
git -C "$RUNNER_TEMP/semgrep-rules" checkout --detach FETCH_HEAD

- name: Scan JavaScript, TypeScript, Node.js, and Express code
run: |
"$RUNNER_TEMP/semgrep-venv/bin/semgrep" scan \
--config p/javascript \
--config p/typescript \
--config p/nodejs \
--config "$RUNNER_TEMP/semgrep-rules/javascript/express/security" \
--sarif \
--output semgrep.sarif \
--exclude node_modules \
--exclude dist \
--exclude build \
--exclude coverage \
.

- name: Upload SARIF to GitHub code scanning
if: success() && (github.repository == '45Drives/45flow' || vars.SEMGREP_SARIF_UPLOAD == 'true') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
uses: github/codeql-action/upload-sarif@3599b3baa15b485a2e49ef411a7a4bb2452e7f93 # v3.30.5
with:
sarif_file: semgrep.sarif
category: semgrep-ce

- name: Retain SARIF report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: semgrep-sarif-${{ github.run_id }}
path: semgrep.sarif
if-no-files-found: warn
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ buildMac.sh

scripts/release/RELEASE_*
.electron-dev-userdata
qa-results/
IMPLEMENTATION_*.md
*.dmg
*.zip
.github/prompts/plan*
.github/agents/*
.github/skills/*
.github/workflows/*
!.github/workflows/security.yml
!.github/workflows/semgrep.yml

RELEASE_GUIDE.md
RELEASE_WORKFLOW.md
Expand All @@ -33,4 +35,4 @@ docs/*Test_Plan*

docs/45Flow-test-plan-*.xlsx
.claude/CLAUDE.md
/docs/project-plans/
docs/project-plans/
Loading
Loading