Delete Firestore provider implementation and tests (5 files). Extract shared
key helpers to new internal/storage/keys.go module. Remove Firestore case
from server bootstrap and storage factory. Drop cloud.google.com/go/firestore
and related dependencies from go.mod. Remove firestore-emulator test targets
from Makefile. Update README storage section to reflect MongoDB-only backend.
coin was registered in the catalog and template default but absent from
the ModulesCSV override in both deploy.yml and samconfig.toml, so the
deployed Lambda never loaded it and all coin_* commands went unregistered.
Add a registration checklist to docs/deploy-aws.md to prevent recurrence.
SAM CLI's --parameter-overrides replaces samconfig.toml's overrides
rather than merging them, so every CI deploy reset the stack's
ModulesCSV to the prior value (which predated the stats module).
The live Lambda's MODULES env was missing stats, so /stats was
dispatched but never handled — the module factory was never called.
The sed-based extraction from samconfig.toml worked locally (BusyBox sed)
but failed in CI with GNU sed:
sed: -e expression #1, char 40: invalid reference \1 on 's' command's RHS
After YAML literal and bash single-quote unescaping, the sed pattern's
parens lacked the BRE \(...\) escaping, so there was no capture group
and \1 was invalid. Rather than fight escape layers for a non-secret
value, just inline the IDs in the workflow.
CI's --parameter-overrides replaces (not merges with) samconfig.toml's
parameter_overrides, so BOT_OWNER_ID was empty in the deployed Lambda.
deploynotify silently skipped sending the post-deploy DM, and all
Protected/Private commands were denied.
Extract the values from samconfig.toml at deploy time so the file
remains the single source of truth for non-secret deploy params.
Also add 'stats' to samconfig.toml's ModulesCSV so local `sam deploy`
doesn't regress the stats module.
CloudFormation's AWS::Scheduler::Schedule Target schema has no property
for HTTPS universal invocation (URL, method, headers) — confirmed
against AWS docs. Switch to the legacy EventBridge Rule path which
supports HTTP targets natively via ApiDestination:
- AWS::Events::Connection: API_KEY auth, presents X-Cron-Token header.
ApiKeyValue stored in EventBridge service-linked secret on stack
update (no per-invoke SSM fetch, AWS-managed secret fees).
- AWS::Events::ApiDestination: POST to ${FunctionUrl}cron/lolschedule_daily_push.
- AWS::Events::Rule: cron(0 1 * * ? *) — daily 01:00 UTC / 08:00 ICT.
Targets ApiDestination with retry x2, 600s max age, DLQ to CronDLQ.
- EventBridgeInvokeRole replaces SchedulerExecutionRole (events.amazonaws.com
principal, events:InvokeApiDestination scoped to this destination only).
NoEcho CronSharedSecret CFN parameter restored; GHA fetches the SSM
SecureString and passes via --parameter-overrides so the value never
appears in template source or stack events.
Free-tier preserved: 1 invocation/day, well under EventBridge Rules +
ApiDestinations free quotas.
Reverts 585d996 + c70b9d0. Both CFN deploys failed at changeset
validation; prod stack was never mutated. Approach A
(AWS::Scheduler::Schedule with arn:aws:scheduler:::http-invoke target)
is unimplementable in pure CloudFormation — the Target schema has no
property for HTTP endpoint/method/headers, regardless of name.
Replacement landing in a follow-up commit.
Restored: plans/reports/brainstorm-260517-1411-eventbridge-schedule-fix.md
(useful design context even though Approach A invalidated).
CloudFormation rejects {{resolve:ssm-secure}} inside
AWS::Scheduler::Schedule HttpInvokeArgs.HeaderParameters (documented
property-allowlist limitation). Add a NoEcho CronSharedSecret parameter
and fetch the SSM SecureString in CI, then pass via --parameter-overrides.
Lambda runtime SSM-fetch flow unchanged.
v9 is the first Node 24-native release and still accepts golangci-lint
>= v2.1.0, so the pinned v2.12.2 binary keeps working. Removes the
final Node 20 deprecation annotation from the CI run.
GitHub forces Node 20 actions to run on Node 24 starting 2026-06-02
and removes Node 20 entirely on 2026-09-16. Bump every action that
emitted the deprecation warning to the latest major that natively
declares runs.using: node24:
actions/checkout v4 -> v6
actions/setup-go v5 -> v6
aws-actions/setup-sam v2 -> v3
aws-actions/configure-aws-credentials v4 -> v6
Verified action.yml runtime declarations (node24) for checkout v6
and setup-go v6. configure-aws-credentials v5 changed only invalid-
boolean-input handling, which we don't pass. setup-sam v3 is solely
the Node bump. golangci-lint-action stays at v7 (already Node 24,
never appeared in the deprecation warning).
Append two steps to .github/workflows/deploy.yml that POST setWebhook
and setMyCommands against the freshly-deployed Function URL, reading
credentials from SSM. Mirrors `make telegram-setup` but inlined to
avoid the Makefile's --profile admin assumption.
Token and webhook-secret are masked via ::add-mask:: before any echo.
Jobs fail loudly on Telegram API errors via `jq -e .ok`.
Mark the manual setWebhook snippets in docs/deploy-aws.md and
docs/deploy-aws-free-tier-guide.md as break-glass.
The deploy workflow no longer relies on a missing AWS_ACCOUNT_ID secret,
preventing invalid assume-role ARNs and matching the repo's documented AWS setup.
Rename:
- Go module github.com/tiennm99/miti99bot-go → github.com/tiennm99/miti99bot
- CloudFormation stack miti99bot-aws-port → miti99bot
- Drop "port", "Cloud Run", "GCP", "cutover", "Phase NN" framing from
active code and docs — project reads as canonical AWS-Lambda from now on.
AWS deploy guide + flow fix:
- New docs/deploy-aws-free-tier-guide.md — Ubuntu 24.04 ARM64 onboarding
with project-local venv (pip awscli + sam-cli), SSM secrets via read -s,
idempotent OIDC provider + role creation, $1 budget alarm.
- Drop sam build from the pipeline — provided.al2023 + makefile builder
expects a Makefile in CodeUri (build/lambda/, the output dir), so the
step always fails. sam deploy --template-file template.yaml now reads
the raw template and zips build/lambda/ directly.
- Rollback section rewritten — use continue-update-rollback /
cancel-update-stack / git-SHA redeploy. Drop the broken
--use-previous-template recipe.
- DynamoDB free-tier row corrected (on-demand is 2.5M read / 1M write
request units, not 25 RCU/WCU).
Updated:
- README.md fully rewritten (drops port/legacy framing, lists modules,
points new users at the free-tier guide).
- aws/README.md retitled "AWS account setup", phase numbers stripped.
- Makefile / .github/workflows/deploy.yml — sam deploy flow.
- samconfig.toml — stack_name = "miti99bot".
- Go comments — Cloud Run → Lambda, Cloud Scheduler → EventBridge
Scheduler, Cloud Logging → CloudWatch Logs.
- Struct field GCPProject → FirestoreProject (env GOOGLE_CLOUD_PROJECT
unchanged).
Plus advisory reports under plans/reports/ from the code-reviewer +
researcher passes that informed the fixes.
Verified: go vet ./..., go build ./..., go test ./... all green.
- golangci-lint-action@v6 doesn't support golangci-lint v2.x; v7 does.
This was the only thing breaking CI; subsequent steps were skipped.
- Firestore emulator step removed for now — storage_test.go skips when
FIRESTORE_EMULATOR_HOST is unset, and the gcloud emulator install
adds 30-60s of CI time for tests not yet on the merge-gating path.
Re-add when storage-layer changes need emulator coverage.
Phase 6 of the 2026-05-09 review remediation plan. Bundle of small
hygiene fixes — none individually urgent but better folded together
than scattered across follow-ups.
- .golangci.yml: enable errcheck/govet/gosec/staticcheck/unused/
ineffassign/gocyclo/misspell/revive. Tuned to the codebase style
(no universal exported-doc requirement, gocyclo cap at 20 to
accommodate handler dispatch). 0 issues across the tree.
- ci.yml: add golangci-lint job + govulncheck (informational).
- Defensive guards:
- registry.go: Module.Name mismatch now errors at Build instead of
silently overwriting (TestBuild_RejectsFactoryNameMismatch).
- cmd/server/main.go: PORT env validated numerically + 0..65535.
- firestore_provider.go: For() re-validates module name; invalid
names return an invalidStore whose every op errors with
ErrInvalidModuleName.
- Dead code removal:
- wordle: gameTTLSeconds const + pickDaily/hashDJB2/todayUTC
helpers + their tests deleted (pickDaily was unused;
daily.go renamed pick_random.go).
- Dependency: golang.org/x/net v0.52.0 -> v0.54.0 (resolves
GO-2026-4918 HTTP/2 infinite-loop CVE).
- Deferred from the original phase plan: Docker digest pinning
(Dependabot handles), per-handler file splits (largest file 279 LOC;
splits would churn for marginal gain).
go test -race -count=1 ./... clean (15 packages); golangci-lint run
clean (0 issues).
Phase 5 of the 2026-05-09 review remediation plan. Closes the
handler-layer test gap (5 modules at 0% coverage in the audit) and
ends the storage-package's CI t.Skip on Firestore emulator tests.
- internal/testutil: Update fixture builders (NewPrivateMessage,
NewGroupMessage, NewSupergroupMessage, NewChannelMessage) plus a
RecordingBot that wraps the real go-telegram/bot.Bot with an
httptest server. The bot library hits the test server instead of
Telegram; multipart form fields are captured per call. Tests assert
on Sent() / LastSent() / AssertSentText().
- Handler tests added: misc (4), util (7), wordle (10), loldle (9),
loldleemoji (8). Cover happy paths, error paths, auth gates,
group-vs-private subject keying, KV side effects.
- Coverage 44.7% -> 69.8% (verified via -coverprofile). All packages
now report coverage in CI output.
- CI: ci.yml installs cloud-firestore-emulator beta component and
starts it on localhost:8090 before go test. Sets
FIRESTORE_EMULATOR_HOST + GOOGLE_CLOUD_PROJECT env so the storage
package's emulator-gated tests execute instead of skipping.
go test -race -count=1 ./... clean across all 15 packages locally.
Implements Phases 02 (partial) and 03 of the go-port-cloud-run plan.
Introduces module framework with per-module KV prefix isolation,
health check endpoint, request timeout protection, and comprehensive
test coverage. Cloud Run deployment deferred to Phase 01.
Security hardening: constant-time secret comparison, cron auth bridge,
and secrets stripped from dependency environment exports. Includes
Dockerfile, GitHub CI workflow (vet + race + build), and integration
tests for module lifecycle.