Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
3b4eff9
Initial work on monetization
Villagers654 May 23, 2026
1a25a49
Merge branch 'develop' into monetization
Villagers654 May 23, 2026
ccca3b5
Clean up donation modal
Villagers654 May 23, 2026
5f5e805
Move project finance management into the project's settings
Villagers654 May 23, 2026
36ea303
nice skeleton for finance manager
Villagers654 May 23, 2026
b95af47
better uh... hitboxes
Villagers654 May 23, 2026
8823a03
allow status modal to fully take over the screen
Villagers654 May 23, 2026
da80998
Properly integrate stripe
Villagers654 May 23, 2026
e5ffbc2
Split finance controllers and services
Villagers654 May 23, 2026
3134052
Merge branch 'develop' into monetization
Villagers654 May 23, 2026
0d530ff
Merge branch 'develop' into monetization
Villagers654 May 23, 2026
90dfe42
Merge develop into monetization
Villagers654 Jun 11, 2026
a9e4e79
Merge develop into monetization
Villagers654 Jun 21, 2026
17b223a
Merge branch 'develop' into monetization
Villagers654 Jun 21, 2026
d1eb664
Merge branch 'main' into monetization
Villagers654 Sep 3, 2026
ba21860
Merge branch 'develop' into monetization
Villagers654 Sep 3, 2026
ef02ba5
Align finance access with admin permissions
Villagers654 Sep 3, 2026
e502a4e
Merge branch 'develop' into monetization
Villagers654 Sep 3, 2026
7333bcd
Merge develop into monetization
Villagers654 Sep 3, 2026
70bcaf6
Merge develop into monetization
Villagers654 Sep 4, 2026
5d7b033
Merge develop into monetization
Villagers654 Sep 8, 2026
cdfd601
Merge develop into monetization
Villagers654 Sep 22, 2026
4f1777b
Merge develop into monetization
Villagers654 Sep 22, 2026
6e8f430
Merge launcher path resolution fix into monetization
Villagers654 Sep 22, 2026
6a552ca
Merge latest develop changes into monetization
Villagers654 Sep 22, 2026
7cf4d78
Merge launcher validation fix into monetization
Villagers654 Sep 22, 2026
1e84e38
Merge latest validated develop changes into monetization
Villagers654 Sep 22, 2026
f7b69fa
Merge wardrobe test synchronization into monetization
Villagers654 Sep 22, 2026
dd47d60
Merge frontend caching and download fixes into monetization
Villagers654 Sep 22, 2026
64c3123
Protect creator balances and build verified payment settlement
Villagers654 Sep 30, 2026
fdef559
Keep push tests running when pull requests have conflicts
Villagers654 Sep 30, 2026
ca2ee33
Add recurring support, protected withdrawals and refund accounting
Villagers654 Sep 30, 2026
f0d001a
Bring monetization up to date with develop
Villagers654 Sep 30, 2026
c68902a
Preserve transfer authorization and pace transaction retries
Villagers654 Sep 30, 2026
29482fe
Expose the finance preview route and verify deployment
Villagers654 Sep 30, 2026
a7ac1f9
Restore protected hydration in the finance preview
Villagers654 Sep 30, 2026
d4bf205
Keep financial reports aligned with wallet balances
Villagers654 Sep 30, 2026
a5ea743
Polish support frequency and populated earnings states
Villagers654 Sep 30, 2026
175daf9
Make optional creator support compact and clear
Villagers654 Sep 30, 2026
d106df9
Preserve owner IDs and project launcher activity
Villagers654 Sep 30, 2026
18ac507
Stage ad revenue evidence without funding creator wallets
Villagers654 Sep 30, 2026
79a67d2
Add provisional ad review and payout readiness states
Villagers654 Sep 30, 2026
7523e8e
Align download controller tests with owner ID tracking
Villagers654 Sep 30, 2026
6b27a3e
Verify support terms and exercise payment pipelines
Villagers654 Sep 30, 2026
093f4c8
Reconcile uncertain payouts against verified transfers
Villagers654 Sep 30, 2026
ef3cc9c
Add audited transfer review controls
Villagers654 Sep 30, 2026
66dace4
Resolve disputes with audited financial evidence
Villagers654 Sep 30, 2026
606349d
Add explicit dispute review and evidence refresh
Villagers654 Sep 30, 2026
4141b3a
Preserve newer recurring support cancellation state
Villagers654 Sep 30, 2026
50af62e
Add payment setup checks and isolated Stripe sandbox tests
Villagers654 Sep 30, 2026
4e693b2
Record verified provider costs without allocating creator debt
Villagers654 Sep 30, 2026
339c00a
Verify initial recurring payments without clock simulation
Villagers654 Sep 30, 2026
558cc14
Stop sandbox checks when a provider assertion fails
Villagers654 Sep 30, 2026
9916d6e
Preserve support errors after session token refresh
Villagers654 Sep 30, 2026
c6d0e71
Recover billing popups and concurrent creator payouts
Villagers654 Oct 1, 2026
3d4054f
Keep recipient review consistent with concurrent confirmations
Villagers654 Oct 1, 2026
b9c2df1
Merge develop into monetization
Villagers654 Oct 2, 2026
7189241
Merge develop cache validation fixes into monetization
Villagers654 Oct 2, 2026
a4750db
Merge develop API diagnostics into monetization
Villagers654 Oct 2, 2026
837fdfa
Merge branch 'develop' into monetization
Villagers654 Oct 2, 2026
1d15824
Merge branch 'develop' into monetization
Villagers654 Oct 2, 2026
ac1678d
Merge branch 'develop' into monetization
Villagers654 Oct 2, 2026
83d0c36
Merge branch 'develop' into monetization
Villagers654 Oct 2, 2026
a1b112c
Merge branch 'develop' into monetization
Villagers654 Oct 2, 2026
39a419d
Merge tested secret bundle lifecycle safeguards
Villagers654 Oct 2, 2026
d6ddc8f
Patch Node runtime and compromised certificate trust
Villagers654 Oct 22, 2026
a1e5172
Update Tomcat and configure trusted Astro hosts
Villagers654 Oct 22, 2026
f51f67a
Resolve remaining frontend dependency security advisories
Villagers654 Oct 22, 2026
4705654
Use patched Node.js in deployment and preview jobs
Villagers654 Oct 22, 2026
06af260
Update remaining Node.js workflow pins
Villagers654 Oct 22, 2026
2e46aa4
Align workflow checks with patched Node.js
Villagers654 Oct 22, 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
31 changes: 23 additions & 8 deletions .github/scripts/should-run-tests-workflow.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ event_name="${GITHUB_EVENT_NAME:-}"
repo="${GITHUB_REPOSITORY:-}"
repo_owner="${GITHUB_REPOSITORY_OWNER:-${repo%%/*}}"
ref_name="${GITHUB_REF_NAME:-}"
head_sha="${GITHUB_SHA:-}"

should_run=true
reason="This workflow run owns the work."
Expand All @@ -13,27 +14,41 @@ gh_available() {
command -v gh >/dev/null 2>&1 && [[ -n "${GH_TOKEN:-}" ]]
}

open_pr_count_for_branch() {
gh api --method GET "repos/$repo/pulls" \
open_pr_can_own_tests() {
local numbers number state mergeable pr_head
numbers="$(gh api --method GET "repos/$repo/pulls" \
-f state=open \
-f head="$repo_owner:$ref_name" \
--jq 'length'
--jq '.[].number')" || return 1
while IFS= read -r number; do
[[ -z "$number" ]] && continue
[[ "$number" =~ ^[0-9]+$ ]] || return 1
state="$(gh api "repos/$repo/pulls/$number" --jq '[.mergeable, .head.sha] | @tsv')" || return 1
IFS=$'\t' read -r mergeable pr_head <<< "$state"
if [[ "$mergeable" == "true" && "$pr_head" == "$head_sha" ]]; then
echo true
return 0
fi
done <<< "$numbers"
echo false
}

# PR runs always own their tests. A queued push may itself skip because a PR
# exists, so its presence cannot prove that the commit has test coverage.
# Conflicted PRs do not trigger pull_request workflows. Unknown mergeability
# or a different head must therefore retain the push run's test coverage.
if [[ "$event_name" == "push" ]]; then
if gh_available && [[ -n "$repo" && -n "$repo_owner" && -n "$ref_name" ]]; then
if open_pr_count="$(open_pr_count_for_branch)"; then
if [[ "$open_pr_count" =~ ^[0-9]+$ && "$open_pr_count" -gt 0 ]]; then
if gh_available && [[ -n "$repo" && -n "$repo_owner" && -n "$ref_name" && "$head_sha" =~ ^[[:xdigit:]]{40}$ ]]; then
if pr_can_own_tests="$(open_pr_can_own_tests)"; then
if [[ "$pr_can_own_tests" == "true" ]]; then
should_run=false
reason="Skipping push workflow because this branch has an open PR; the pull_request run owns this commit."
reason="Skipping push workflow because an open, mergeable PR has this exact head; the pull_request run owns this commit."
fi
else
echo "::warning::Could not check for open pull requests; running tests to avoid missing coverage."
fi
else
echo "::warning::GitHub CLI or token unavailable; running tests to avoid missing coverage."
echo "::warning::GitHub CLI, token, or commit context unavailable; running tests to avoid missing coverage."
fi
fi

Expand Down
2 changes: 1 addition & 1 deletion .github/tests/dev-responsiveness-diagnostic.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ test('workflow is manual, develop-only, credential-free and standard-runner with
assert.ok(!/^ (push|pull_request|schedule):/m.test(workflow));
assert.match(workflow, /github\.ref_name == 'develop'/);
assert.match(workflow, /runs-on: ubuntu-latest/);
assert.match(workflow, /node-version: 22\.23\.3/);
assert.match(workflow, /node-version: 22\.23\.4/);
assert.ok(!/DIAGNOSTIC_TOOL_ROOT: \$\{\{ runner\./.test(workflow));
assert.match(workflow, /export DIAGNOSTIC_TOOL_ROOT="\$RUNNER_TEMP\/modtale-diagnostic-tools"/);
assert.match(workflow, /contents: read/);
Expand Down
41 changes: 37 additions & 4 deletions .github/tests/workflow-scripts.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function run(script, overrides = {}) {
GITHUB_REPOSITORY: 'Modtale/modtale',
GITHUB_REPOSITORY_OWNER: 'Modtale',
GITHUB_REF_NAME: 'audit',
GITHUB_SHA: 'a'.repeat(40),
GH_TOKEN: 'test-token',
...overrides,
},
Expand All @@ -42,14 +43,46 @@ test('PR creation and synchronization always retain their own test coverage', ()
}
});

test('push skips only when the GitHub API confirms an open PR', () => {
function mockPullRequestApi() {
const bin = path.join(directory, 'bin');
fs.mkdirSync(bin);
const gh = path.join(bin, 'gh');
fs.writeFileSync(gh, '#!/bin/sh\nprintf "1\\n"\n', { mode: 0o755 });
const env = { GITHUB_EVENT_NAME: 'push', PATH: `${bin}${path.delimiter}${process.env.PATH}` };
fs.writeFileSync(gh, `#!/bin/sh
case "$*" in
*"/pulls/"*)
[ "\${MOCK_PR_ERROR:-}" = "yes" ] && exit 1
printf '%s\\t%s\\n' "\${MOCK_MERGEABLE:-true}" "\${MOCK_HEAD:-$GITHUB_SHA}"
;;
*) printf '%s\\n' "\${MOCK_PR_NUMBERS-25}" ;;
esac
`, { mode: 0o755 });
return { GITHUB_EVENT_NAME: 'push', PATH: `${bin}${path.delimiter}${process.env.PATH}` };
}

test('push skips only when an open PR is positively mergeable at the same head', () => {
const env = mockPullRequestApi();
assert.match(run('should-run-tests-workflow.sh', env), /^should_run=false$/m);
fs.writeFileSync(gh, '#!/bin/sh\nexit 1\n', { mode: 0o755 });
});

test('conflicted, unknown, stale, and absent PRs keep push tests enabled', () => {
const env = mockPullRequestApi();
for (const scenario of [
{ MOCK_MERGEABLE: 'false' },
{ MOCK_MERGEABLE: 'null' },
{ MOCK_MERGEABLE: 'unexpected' },
{ MOCK_HEAD: 'b'.repeat(40) },
{ MOCK_PR_NUMBERS: '' },
{ MOCK_PR_NUMBERS: 'not-a-number' },
{ MOCK_PR_ERROR: 'yes' },
{ GITHUB_SHA: '' },
]) {
assert.match(run('should-run-tests-workflow.sh', { ...env, ...scenario }), /^should_run=true$/m);
}
});

test('PR-list API failure keeps push tests enabled', () => {
const env = mockPullRequestApi();
fs.writeFileSync(path.join(directory, 'bin', 'gh'), '#!/bin/sh\nexit 1\n', { mode: 0o755 });
assert.match(run('should-run-tests-workflow.sh', env), /^should_run=true$/m);
});

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/api-cache-header-diagnostic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22.23.3
node-version: 22.23.4
- name: Validate fixed environment and unit guards
run: |
node .github/scripts/api-cache-header-diagnostic.mjs validate
Expand Down
42 changes: 32 additions & 10 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Modtale CI/CD
name: Modtale CI/CD

on:
push:
Expand Down Expand Up @@ -56,6 +56,11 @@ jobs:
launcher_artifact_prefix: ${{ steps.launcher_metadata.outputs.artifact_prefix }}

steps:
- name: Set up patched Node.js
uses: actions/setup-node@v4
with:
node-version: 22.23.4

- uses: actions/checkout@v4
with:
fetch-depth: 0
Expand Down Expand Up @@ -105,7 +110,7 @@ jobs:
fi
echo "GIT_BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
echo "BRANCH_SLUG=$BRANCH_SLUG" >> $GITHUB_ENV

if [ "$BRANCH_NAME" = "main" ]; then
echo "ENV_TYPE=prod" >> $GITHUB_ENV
echo "BUILD_SERVICE_ACCOUNT=${{ vars.GCP_BUILD_SERVICE_ACCOUNT }}" >> $GITHUB_ENV
Expand All @@ -130,7 +135,7 @@ jobs:
echo "WARDEN_ENABLED=true" >> $GITHUB_ENV
echo "OAUTH_ENABLED=true" >> $GITHUB_ENV
echo "WARDEN_SECRET_NAME=WARDEN_API_KEY" >> $GITHUB_ENV

elif [ "$BRANCH_NAME" = "develop" ]; then
echo "ENV_TYPE=dev" >> $GITHUB_ENV
echo "BUILD_SERVICE_ACCOUNT=${{ vars.GCP_BUILD_SERVICE_ACCOUNT }}" >> $GITHUB_ENV
Expand All @@ -155,7 +160,7 @@ jobs:
echo "WARDEN_ENABLED=true" >> $GITHUB_ENV
echo "OAUTH_ENABLED=true" >> $GITHUB_ENV
echo "WARDEN_SECRET_NAME=WARDEN_API_KEY" >> $GITHUB_ENV

else
SLUG="$BRANCH_SLUG"
BRANCH_PREVIEW_SOURCE_R2_BUCKET_NAME="${{ vars.GCP_BRANCH_PREVIEW_SOURCE_R2_BUCKET_NAME }}"
Expand Down Expand Up @@ -511,7 +516,7 @@ jobs:
else
echo "Reusing the existing backend image for a configuration-only rollout."
fi

ARGS=(
"--image" "gcr.io/$PROJECT_ID/modtale-backend:${{ env.TAG }}"
"--region" "$REGION"
Expand Down Expand Up @@ -766,7 +771,8 @@ jobs:
: "${RUNTIME_SERVICE_ACCOUNT:?Set the GitHub environment runtime service account variable for this environment.}"

bash ../.github/scripts/build-container.sh frontend "$TAG" \
--build-arg "PUBLIC_API_URL=$API_URL" --build-arg "SSR_API_URL=$SSR_API_URL"
--build-arg "PUBLIC_API_URL=$API_URL" --build-arg "SSR_API_URL=$SSR_API_URL" \
--build-arg "PUBLIC_FINANCE_DEMO=${{ env.ENV_TYPE == 'preview' && 'true' || 'false' }}"

FRONTEND_ARGS=(
"--image" "gcr.io/$PROJECT_ID/modtale-frontend:$TAG"
Expand Down Expand Up @@ -838,6 +844,12 @@ jobs:
echo "FINAL_FRONTEND_URL=${{ env.FRONTEND_DOMAIN }}" >> $GITHUB_ENV
fi

- name: Verify synthetic finance preview route
if: env.ENV_TYPE == 'preview' && (steps.filter.outputs.frontend == 'true' || env.FRONTEND_EXISTS == 'false')
run: |
curl --fail --silent --show-error --retry 4 --retry-delay 3 "$FINAL_FRONTEND_URL/finance-preview" -o /tmp/finance-preview.html
grep -Fq '<title>Finance demo' /tmp/finance-preview.html

- name: Update Backend CORS and Self-Awareness
id: update_backend_self_awareness
# Only preview URLs are unknown during the initial backend deploy. Production
Expand All @@ -857,7 +869,7 @@ jobs:
else
PUBLIC_BACKEND_URL=$B_URL
fi

if [ "$MODTALE_SECRET_BUNDLES_ENABLED" = "true" ]; then
python3 .github/scripts/secret_bundle_ci.py deploy -- \
--update-env-vars "FRONTEND_URL=$FINAL_FRONTEND_URL,BACKEND_URL=$PUBLIC_BACKEND_URL" >/dev/null
Expand Down Expand Up @@ -953,21 +965,21 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Component | Status | Target Service | Service URL |" >> $GITHUB_STEP_SUMMARY
echo "|---|---|---|---|" >> $GITHUB_STEP_SUMMARY

if [ -n "$PUBLIC_API_URL" ]; then
echo "| **Backend API** | $BACKEND_STATUS | \`${{ env.BACKEND_SERVICE }}\` | [API Endpoint]($PUBLIC_API_URL) |" >> $GITHUB_STEP_SUMMARY
elif [ -n "$B_URL" ]; then
echo "| **Backend API** | $BACKEND_STATUS | \`${{ env.BACKEND_SERVICE }}\` | [API Endpoint]($B_URL/api/v1) |" >> $GITHUB_STEP_SUMMARY
else
echo "| **Backend API** | $BACKEND_STATUS | \`${{ env.BACKEND_SERVICE }}\` | *N/A* |" >> $GITHUB_STEP_SUMMARY
fi

if [ -n "$F_URL" ]; then
echo "| **Frontend App** | $FRONTEND_STATUS | \`${{ env.FRONTEND_SERVICE }}\` | [App URL]($F_URL) |" >> $GITHUB_STEP_SUMMARY
else
echo "| **Frontend App** | $FRONTEND_STATUS | \`${{ env.FRONTEND_SERVICE }}\` | *N/A* |" >> $GITHUB_STEP_SUMMARY
fi

echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "*View deployment details in [Google Cloud Console](https://console.cloud.google.com/run?project=${{ env.PROJECT_ID }}).* " >> $GITHUB_STEP_SUMMARY
Expand Down Expand Up @@ -1154,6 +1166,11 @@ jobs:
R2_TOKEN_NAME: modtale-preview-template-reader
RUNTIME_SERVICE_ACCOUNT: ${{ vars.GCP_BRANCH_PREVIEW_RUNTIME_SERVICE_ACCOUNT }}
steps:
- name: Set up patched Node.js
uses: actions/setup-node@v4
with:
node-version: 22.23.4

- uses: actions/checkout@v4
- name: Resolve environment-specific bundle settings
env:
Expand Down Expand Up @@ -1246,6 +1263,11 @@ jobs:
id-token: write

steps:
- name: Set up patched Node.js
uses: actions/setup-node@v4
with:
node-version: 22.23.4

- name: Prepare cleanup names
env:
DELETED_BRANCH: ${{ matrix.branch }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dev-responsiveness-diagnostic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22.23.3
node-version: 22.23.4

- name: Validate fixed dev target and bounded inputs
run: node .github/scripts/dev-responsiveness-diagnostic.mjs validate
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/mock-db-refresh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22.12.0
node-version: 22.23.4

- name: Install mock DB tooling
working-directory: mock-db
Expand Down
15 changes: 15 additions & 0 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ jobs:
head_repo: ${{ steps.resolve.outputs.head_repo }}
head_sha: ${{ steps.resolve.outputs.head_sha }}
steps:
- name: Set up patched Node.js
uses: actions/setup-node@v4
with:
node-version: 22.23.4

- id: resolve
name: Validate maintainer command
env:
Expand Down Expand Up @@ -139,6 +144,11 @@ jobs:
PR_HEAD_SHA: ${{ needs.command.outputs.head_sha }}

steps:
- name: Set up patched Node.js
uses: actions/setup-node@v4
with:
node-version: 22.23.4

- name: Validate preview isolation config
run: |
: "${PROJECT_ID:?Set repository variable GCP_PREVIEW_PROJECT_ID to a dedicated preview GCP project.}"
Expand Down Expand Up @@ -493,6 +503,11 @@ jobs:
CLOUDFLARE_R2_JURISDICTION: ${{ vars.CLOUDFLARE_R2_JURISDICTION }}

steps:
- name: Set up patched Node.js
uses: actions/setup-node@v4
with:
node-version: 22.23.4

- name: Check out trusted cleanup scripts
uses: actions/checkout@v4
with:
Expand Down
Loading
Loading