Commit Graph

14 Commits

Author SHA1 Message Date
kjh2064 24ec410f3d feat(web): publish version.txt in build pipeline for deterministic live server versioning
Validators (Pushes and Pull Requests) / validate-ui-and-storage (push) Successful in 16s
Validators (Pushes and Pull Requests) / validate-core (push) Successful in 1m46s
2026-07-12 14:05:10 +09:00
kjh2064 c6f269e30a ci(gitea): serialize pipeline into Validators -> Prepare Release -> Deploy sequence
Validators (Pushes and Pull Requests) / validate-ui-and-storage (push) Successful in 23s
Validators (Pushes and Pull Requests) / validate-core (push) Successful in 2m7s
2026-07-12 13:51:59 +09:00
kjh2064 f8ff3a2c46 ci: chain release build into production deploy
Validators (Pushes and Pull Requests) / validate-ui-and-storage (push) Successful in 22s
Prepare Release / Build & Create Release (push) Successful in 1m0s
Prepare Release / Release Notification (push) Successful in 1s
Validators (Pushes and Pull Requests) / validate-core (push) Successful in 1m55s
2026-07-12 12:59:27 +09:00
kjh2064 4b29fafcff fix: Use KST (Asia/Seoul) instead of UTC for release date component
User caught this directly: it's already 2026-07-12 in Korea, but
Run #2008's release was tagged quant_20260711.3.7150737 -- the wrong
date.

Confirmed: UTC was still 2026-07-11 16:2x when KST was already
2026-07-12 01:2x (9-hour offset). prepare-release.yml computed
TODAY via `TZ=UTC date +%Y%m%d`, which is only "correct" if the team
operates on UTC -- but this project's production server logs,
deployment cadence, and team are all Korea Standard Time. Any release
cut between midnight and 9am KST would silently tag itself with
yesterday's date.

Fixed by using `TZ=Asia/Seoul date +%Y%m%d` instead.
2026-07-12 01:29:14 +09:00
kjh2064 71507374ca fix: Reset release sequence number to 0 on each new date
Per spec: the sequence number is a per-day counter that resets on
date change and starts at 0, not 1. The first release of a day is
quant_YYYYMMDD.0.hash, the second .1, etc.

Previous commit fixed *counting* today's releases via the Gitea API
(instead of the always-empty local git tags from a shallow checkout),
but still added +1 on top, which would have produced 1, 2, 3... for
the first, second, third releases of a day instead of 0, 1, 2.
DEPLOY_COUNT is now just RELEASES_TODAY directly.
2026-07-12 01:23:56 +09:00
kjh2064 4d2c23221a fix: Count today's releases via Gitea API instead of local git tags
User asked why every release tonight had the same "sequence number"
(quant_20260711.1.*) despite creating three of them. Confirmed via
API: tags b7591fb, 6ab270f, and e49922e all exist for 2026-07-11, all
claiming to be deploy #1.

Root cause: `actions/checkout@v4` (no fetch-depth/fetch-tags options)
does a shallow, tags-less clone by default. Each prepare-release.yml
run happens in a brand-new container, so `git tag -l "quant_${TODAY}.*"`
always sees zero local tags regardless of how many releases actually
exist -- DEPLOY_COUNT was permanently stuck at 0+1=1.

Fix: query GET /repos/{repo}/tags via the Gitea API (same token/curl
pattern already used elsewhere in this workflow) to count today's
actual tags, instead of relying on the job's local, incomplete git
state.
2026-07-12 01:23:04 +09:00
kjh2064 e49922e188 fix(security): Remove hardcoded DB password from release artifact
Production incident: quant.taxbaik.com/login threw 28P01 (password
authentication failed) after the July 7 deployment's
appsettings.Production.json carried a stale DB password. Root cause
chain:

1. The DB password for quantengine_app had been rotated at some
   point; the new password was saved to
   /home/kjh2064/.config/quantengine.env on the server, but that
   file was never wired into the quantengine.service systemd unit
   (no EnvironmentFile= directive), so it was silently unused.
2. Every appsettings.Production.json we've generated in CI
   (including tonight's prepare-release.yml) baked in a PLACEHOLDER
   password ("quantengine_app") that was never the real credential
   to begin with -- copied forward from an earlier debugging session
   without ever being verified against the live DB.

Immediate production fix (out of band, via SSH): patched the active
deployment's appsettings.Production.json with the current working
password (verified via direct psql connection) and restarted the
service. Login confirmed HTTP 200 with a clean journalctl afterward.

This commit fixes the root cause in the pipeline: prepare-release.yml
no longer writes a ConnectionStrings block into the artifact at all.
Baking any DB password (even a correct one) into a build artifact
that ships as a downloadable Gitea Release asset is unsafe and goes
stale on every credential rotation. The correct fix is for
quantengine.service to load ConnectionStrings__DefaultConnection from
/home/kjh2064/.config/quantengine.env via systemd's EnvironmentFile=,
which overrides appsettings.Production.json at runtime per standard
ASP.NET Core configuration precedence. That unit-file edit requires
interactive sudo and must be applied by hand on the server (tracked
separately, not part of this commit).

IMPORTANT: the release quant_20260711.1.6ab270f already published
tonight was built before this fix and still lacks any DB config --
do not deploy it via deploy-prod.yml until the systemd
EnvironmentFile wiring is confirmed on the server, or the login
outage will recur.
2026-07-12 00:28:13 +09:00
kjh2064 6ab270fe92 fix: Replace gh CLI with direct Gitea API calls (curl)
Root cause found via SSH log analysis (actions_log/.../2326.log):
  'gh release create' failed with exit code 127 (command not found).
  The act_runner Docker image used for jobs does not ship the
  GitHub CLI (gh), so any step relying on it fails immediately.

Fix: Replace gh CLI calls with direct Gitea REST API calls using
curl, which is available in the base image:
  1. POST /repos/{repo}/releases -- create release, parse id via python3
  2. POST /repos/{repo}/releases/{id}/assets -- upload artifact as multipart

This removes the gh CLI dependency entirely and matches how
deploy-prod.yml already talks to Gitea (curl + REST API).
2026-07-12 00:18:29 +09:00
kjh2064 b7591fb381 fix: Resolve git tag creation failure due to unset git identity
Root cause found via SSH log analysis (actions_log/.../2324.log):
  'git config user.name' returned exit code 1 (no global identity set
  in the Gitea Actions runner container), and since the step uses
  'bash -e -o pipefail', the script aborted immediately at that line
  before ever reaching 'git tag'.

Fix: explicitly set git user.name/user.email before tagging, and
remove the fragile bare 'git config user.name' debug calls.
Also removed the '|| echo ...continuing' fallback on git push so
push failures are now visible as real failures instead of swallowed.
2026-07-12 00:16:14 +09:00
kjh2064 02c7bdaeda debug: Add detailed logging to prepare-release.yml
- Add git config output for debugging tag creation
- Add artifact existence check
- Add gh CLI version check
- Add explicit --repo parameter for gh release create
- Make tag push non-fatal to continue workflow
2026-07-11 23:59:11 +09:00
kjh2064 9778a3ded1 fix: Simplify release notes format to fix YAML parsing error
- Remove multiline formatting from --notes argument
- Use single-line format to avoid YAML syntax errors
- Version and Commit info preserved in notes
2026-07-11 23:46:40 +09:00
kjh2064 375cd7694e fix: Correct notification job condition in prepare-release.yml
- Change job-level if: success() to if: always()
- Use step-level condition: if: needs.build-and-release.result == 'success'
- Fixes Gitea Actions compatibility issue
2026-07-11 23:36:48 +09:00
kjh2064 f2938c232a fix: Update prepare-release.yml with version auto-generation
- Auto-generate version format: quant_YYYYMMDD.count.hash
- Count existing tags for today to determine deploy count
- Add job outputs for version and commit
- Simplify release notes format to fix YAML parsing error
- Make version input optional (auto-generated if empty)
2026-07-11 23:35:48 +09:00
kjh2064 352b440e8d feat(ci/cd): Implement release-based deployment with two-workflow architecture
- Add prepare-release.yml: Manual release creation workflow
  * Builds code, generates appsettings.Production.json
  * Packages artifact (.tar.gz)
  * Creates git tag and Gitea Release with attached artifact

- Refactor deploy-prod.yml: Release-based deployment workflow
  * Fetch Release stage: Query Gitea Releases, download artifact
  * Pre-Check stage: Verify SSH credentials and release integrity
  * Deploy stage: Upload, extract, symlink, restart service
  * Health Check stage: 5-point verification (HTTP, CSS, login, service, release)
  * Report stage: Final deployment status
  * Now triggered via workflow_dispatch with release version input
  * Removes on:push trigger (manual release selection required)

- Update CLAUDE.md:
  * Document two-workflow architecture
  * Add release creation and deployment procedures
  * Update SSH key configuration with GITEA_TOKEN requirement
  * Clarify CI/CD-Only Deployment Mandate with release traceability
  * Add complete deployment flow documentation

**Motivation**:
- Separate build/release phase from deployment phase
- Enable release tagging for version control and rollback
- Reduce build time on re-deployments (use cached releases)
- Improve deployment auditability via git tags and Gitea Releases
- Match taxbaik-pattern release management strategy

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-11 23:21:20 +09:00