Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
2084 commits
Select commit Hold shift + click to select a range
66d5402
fix(gcp): stamp PaymentOption=monthly on all GCP recs (closes #718) (…
cristim Jul 17, 2026
b09516a
fix(ui): enforce future-only planned start date + widen Configure Pur…
cristim Jul 17, 2026
5663254
fix(purchases): correct Savings History chart axis, tooltip decimals,…
cristim Jul 17, 2026
8f9347e
fix(db): rename status value cancelled->canceled (expand-contract, US…
cristim Jul 17, 2026
7465a46
ux(recommendations): cascading categorical filter distinct values (cl…
cristim Jul 17, 2026
464a235
sec(iac): remove SecretsManagerDescribe wildcard block (closes #430) …
cristim Jul 17, 2026
4aa4ead
sec(ci): gate terraform force-unlock behind explicit input (closes #4…
cristim Jul 17, 2026
14ae9cf
sec: digest-pin Dockerfile.dev base image (closes #421) (#857)
cristim Jul 17, 2026
d29a3e0
sec(frontend): pin npm deps to exact lockfile versions (closes #425) …
cristim Jul 17, 2026
185ca42
chore(iac/aws/networking): remove redundant Secrets Manager VPC endpo…
cristim Jul 17, 2026
4b04849
ci(pre-commit): fetch Trivy installer from pinned release tag (#1238)
cristim Jul 17, 2026
8cd51ab
ci: bump gosec to v2.28.0, retire obsolete #nosec suppressions (close…
cristim Jul 17, 2026
1fca7fd
feat(frontend/history): inline column filters via shared lib (refs #1…
cristim Jul 17, 2026
bc4d3ae
feat(settings): configurable EC2 RI OfferingClass (closes #694) (#847)
cristim Jul 17, 2026
c10989d
fix(scheduledauth): use hardened HTTP client for JWKS warmup and fetc…
cristim Jul 17, 2026
7331906
fix(api/history): gate approval-expiry sweep on Lambda runtime (#1232)
cristim Jul 17, 2026
f63400a
fix(aws/savingsplans): purchase EC2Instance SP for the recommended fa…
cristim Jul 17, 2026
dd569a0
fix(api/marketplace): convert RI term years->months in resale pricing…
cristim Jul 17, 2026
b66e854
fix(purchase): gate sweep/SQS execution on AutoPurchase, fail-loud on…
cristim Jul 17, 2026
67c0fd8
fix(api): gate empty-account history rows on ownership + enforce API-…
cristim Jul 17, 2026
97e6f5c
fix(db/migrate): refuse to auto-heal dirty migrations without verifyi…
cristim Jul 17, 2026
79f6c6d
fix(iac/aws): scope Fargate SES send to email_from_domain (match Lamb…
cristim Jul 17, 2026
bd1db20
fix(api): current_savings zero for services with no active commitment…
cristim Jul 17, 2026
1d9f1b8
fix(aws/recommendations): protect RateLimiter against concurrent acce…
cristim Jul 17, 2026
849a76e
fix(providers): correct Azure resourceType filters + fail-loud SP mon…
cristim Jul 19, 2026
0249167
fix(db): write canonical 'canceled' on all cancel paths + cleanup fil…
cristim Jul 19, 2026
e899c61
fix(api/dashboard): exclude revoked commitments, stop fabricating cur…
cristim Jul 19, 2026
f0660b9
chore(make): drop broken recipes, pin dev tools, add ci to .PHONY (#1…
cristim Jul 19, 2026
32a2399
fix(deploy): forward extra terraform args, drop vestigial targets (#1…
cristim Jul 19, 2026
c8578d3
docs(claude): fix build/test commands and file layout in CLAUDE.md (#…
cristim Jul 19, 2026
1449a16
fix(terraform): align provider version floors across modules (#1242)
cristim Jul 19, 2026
48b4d94
test(cmd): funnel goroutine results to test goroutine in alias test (…
cristim Jul 19, 2026
7465a9e
docs(api): document 403 on permission-gated routes (#884)
cristim Jul 19, 2026
4fa4c64
test(azure): concurrency timing test for parallel dispatcher (closes …
cristim Jul 19, 2026
cc8ff3c
log: silence 'service config not found' on per-rec lookup (closes #26…
cristim Jul 19, 2026
68b9cda
refactor(frontend/plans): drop redundant setPlanAccounts call (closes…
cristim Jul 19, 2026
8bd3299
docs: codify known_issues resolved-sweep convention (closes #141) (#860)
cristim Jul 19, 2026
6abb39a
test(api/auth): fix brittle mock string in resetPassword test (closes…
cristim Jul 19, 2026
68e361d
refactor(frontend): consolidate account-overrides prefetch helper (cl…
cristim Jul 19, 2026
8fb9efd
chore(ci): document/add Frontend build (PR) as required status check …
cristim Jul 19, 2026
f7c88ba
feat(recommendations): server-side pushdown for service/region/accoun…
cristim Jul 19, 2026
f6f1377
refactor(azure): consolidate AzureRetailPrice into shared pricing pac…
cristim Jul 19, 2026
222b450
feat(common): cross-provider compute capacity ranking via VCPU+Memory…
cristim Jul 19, 2026
673f1f0
audit(aws): surface OpenSearch RI tag-failure for ops monitoring (clo…
cristim Jul 19, 2026
934a0d9
docs(purchase): defer savings-plans alias drop to 2026-10-30 (closes …
cristim Jul 19, 2026
0ef84f3
feat(commitmentopts): use AWS SP probe in Validate path (closes #134)…
cristim Jul 19, 2026
6d42551
audit(reshape): verify CE-driven cross-family alternatives (closes #1…
cristim Jul 19, 2026
7b47b7c
feat(email): multipart HTML+plaintext for RI exchange pending approva…
cristim Jul 19, 2026
9b020e8
docs(security/azure): fix post-apply recipe (Consumption SKU) (#184)
cristim Jul 19, 2026
44427ba
docs(README): document per-account service overrides (closes #117) (#…
cristim Jul 19, 2026
5c267c5
docs(README): document four per-plan-type --services slugs (closes #1…
cristim Jul 19, 2026
c848a07
fix(exchange): enforce daily-cap integrity on manual path, actual-pai…
cristim Jul 19, 2026
c265ab2
chore(reliability): recover() in fire-and-forget goroutines (closes #…
cristim Jul 19, 2026
6421e0e
chore(dev): add go.work for gopls multi-module workspace (closes #516…
cristim Jul 19, 2026
5c0c273
test(archera): extend federation handler matrix to CLI/ARM (closes #3…
cristim Jul 19, 2026
dc1e2fa
feat(gcp): populate RecurringMonthlyCost in GCP rec parsers (closes #…
cristim Jul 19, 2026
0f7d0fe
chore(providers/aws): quarterly audit of findOfferingID, closes #515 …
cristim Jul 19, 2026
0479b99
fix(aws/recommendations): reject NaN/Inf in SP money parsing (follow-…
cristim Jul 19, 2026
95ecd19
docs(workflow): require PRs to mirror closing issue triage labels, cl…
cristim Jul 19, 2026
eb442e8
fix(aws/opensearch): validate RI count before idempotency short-circu…
cristim Jul 19, 2026
cc30a93
perf(azure database): batched per-server AZConfig lookup, closes #149…
cristim Jul 19, 2026
3a5ffc8
chore(common): rename ServiceSavingsPlans -> ServiceSavingsPlansAll, …
cristim Jul 19, 2026
702b886
refactor(api): requireAuth returns resolved Principal (closes #194) (…
cristim Jul 19, 2026
ee021c7
test(api): inject resolveAccount into buildReshapeHandler (#192) (#862)
cristim Jul 19, 2026
a3dd1b1
fix(purchase): gate scheduler/SQS on typed web source constant (follo…
cristim Jul 19, 2026
f7a4fbd
fix(db): add missing offering columns to GetActivePurchaseHistory SEL…
cristim Jul 20, 2026
a6665b5
fix(cmd): use portable os.Stdin.Fd for password read on Windows (foll…
cristim Jul 20, 2026
299b6fd
fix(aws/recommendations): complete NaN/Inf money guards across parser…
cristim Jul 20, 2026
22f62a5
fix(lint): replace deferred rollback nolint with explicit error handl…
cristim Jul 20, 2026
54f49d6
test(providers/azure): make IsConfigured guards deterministic (closes…
cristim Jul 20, 2026
2c67850
fix(azure/managedredis): pass subscription scope (not filter) to reco…
cristim Jul 20, 2026
56e1bee
docs: backfill exported docstrings to clear 80% coverage gate (closes…
cristim Jul 21, 2026
4f6ca50
test(azure): mock credentials and service APIs in all Azure tests (#1…
cristim Jul 21, 2026
f10f9ea
refactor(oidc): inject Azure Key Vault client factory (closes #1464) …
cristim Jul 21, 2026
c1cf552
test(providers/azure): reuse shared mocks in synapse/managedredis (cl…
cristim Jul 21, 2026
1efb314
refactor(api): inject Azure revoke client factory (#1471)
cristim Jul 21, 2026
427e81b
fix(api): propagate authenticated principal through handlers (#1476)
cristim Jul 21, 2026
63c7a90
test(aws/recs): cover SizeInMiB-nil + assert no NextPage on canceled …
cristim Jul 21, 2026
206b6e4
feat(cli): end-of-run summary of dropped recommendations (closes #361…
cristim Jul 21, 2026
6573d76
feat(notifications): per-recipient mute + List-Unsubscribe (closes #2…
cristim Jul 21, 2026
d2e52d9
chore(deploy): remove orphaned internal/deploy package (#1246)
cristim Jul 21, 2026
9bfca74
fix(deps): bump golang.org/x/text to v0.39.0 (GO-2026-5970) (#1484)
cristim Jul 22, 2026
1cc33d3
fix(frontend/deps): resolve fast-uri and svgo high-severity advisorie…
cristim Jul 22, 2026
f8cdea6
fix(server): decode base64 Lambda Function URL request bodies before …
cristim Jul 22, 2026
602774f
fix(auth): bind MaxPurchaseAmount to total commitment, enforce on ret…
cristim Jul 22, 2026
ae7b61b
fix(aws/ladder): scope RI utilization query to EC2+region for reshape…
cristim Jul 22, 2026
75e5e2b
fix(oidc): provision EC P-256 signing keys in Terraform to match ES25…
cristim Jul 22, 2026
c59c116
fix(aws/ec2): reject unrecognized RI term instead of silently default…
cristim Jul 22, 2026
4be321d
fix(auth): honor admin carve-outs on bearer-session permission checks…
cristim Jul 22, 2026
0ae6c6a
fix(api): authorize API-key clients on delete/cancel purchase permiss…
cristim Jul 22, 2026
6a8ee07
fix(marketplace): fail loud instead of listing no-upfront RIs at $0 (…
cristim Jul 22, 2026
1dea72c
fix(auth): scope ladder configs to the caller's allowed accounts (#1489)
cristim Jul 22, 2026
59db0f1
test(recommendations): scaffolding for E2E smoke (WIP for #167) (#394)
cristim Jul 22, 2026
70c9a7b
fix(api): COALESCE cancel actor across canceled_by/cancelled_by on re…
cristim Jul 22, 2026
fc5460d
fix(iac/aws): grant deploy role KMS key-lifecycle for OIDC signing-ke…
cristim Jul 23, 2026
f0f7d2f
feat(api,frontend): 4-eyes approval mode — creator cannot self-approv…
cristim Jul 23, 2026
5f134a0
fix(cli): remove --dry-run flag; --purchase alone executes real purch…
cristim Jul 23, 2026
294892d
fix(frontend/mobile): add inputmode/autocomplete/autocapitalize hints…
cristim Jul 23, 2026
e1a3172
test(frontend/mobile): regression coverage for #989 44x44 touch minim…
cristim Jul 23, 2026
d9eb097
fix(frontend/mobile): bottom-sheet modal at <=480px + vw cap on .moda…
cristim Jul 23, 2026
ab682d9
fix(frontend): resolve high-severity npm audit vulns reddening Securi…
cristim Jul 27, 2026
b83c5d1
fix(iac/aws): create_before_destroy on OIDC signing key (follow-up to…
cristim Jul 27, 2026
b90b420
fix(iac/aws): case-insensitive tag match on kms:GetKeyPolicy deploy g…
cristim Jul 27, 2026
99854f5
feat(api): owner-token compare-and-clear for collection in-flight mar…
cristim Jul 27, 2026
7b18bfd
fix(deps): bump grpc to v1.82.1 to clear GO-2026-6061 (#1529)
cristim Jul 27, 2026
101f099
refactor(common): make DatabaseDetails/CacheDetails pointer-only (#1525)
cristim Jul 27, 2026
be11bdc
chore(make): add docker-skip convenience target to Makefile.terraform…
cristim Jul 27, 2026
3e9660d
fix(azure): coerce web partial-upfront to monthly, not upfront (#1503…
cristim Jul 28, 2026
887d51f
feat(mcp): CUDly MCP server for RI/SP/CUD purchases across AWS, Azure…
cristim Jul 28, 2026
3e0400b
sec(iac/aws): require OIDC subject claim in aws-target CloudFormation…
cristim Jul 28, 2026
ecb0681
feat(azure/ri-exchange): find compatible offerings and execute exchan…
cristim Jul 28, 2026
1635486
feat(plans): per-plan health-score badge (closes #376 scope) (#1521)
cristim Jul 28, 2026
5f850f2
fix(ci): stop interpolating dispatch inputs into rollback run blocks …
cristim Jul 28, 2026
3fc9b57
fix(arm): pin GCP WIF attribute condition and narrow SA grant (#1651)
cristim Jul 28, 2026
1dbff53
fix(purchase): keep account scope on per-account retry successors (#1…
cristim Jul 28, 2026
6ded401
fix(iac/aws): grant kms:TagResource for KMS CreateKey tag-on-create (…
cristim Jul 28, 2026
a826688
fix(iac/aws): extend OIDC trust allowlist to cover every job assuming…
cristim Aug 3, 2026
9de48ae
fix(db): widen purchase_history.account_id to VARCHAR(255) (#1677)
cristim Aug 3, 2026
f6bb36a
sec(ci): bind destroy jobs to an environment and narrow id-token on d…
cristim Aug 3, 2026
cd4ee03
sec(iac/aws): reject the all-zeros OIDC thumbprint in the aws-target …
cristim Aug 3, 2026
218f385
fix(ci): pin hadolint image by digest to stop drift off the rev pin (…
cristim Aug 3, 2026
a233ce0
feat(admin): per-API-key usage stats + summary card (closes #380 scop…
cristim Aug 3, 2026
b117634
feat(azure): org-wide multi-subscription recommendation collection (c…
cristim Aug 3, 2026
1e1e7e4
chore(docker): adopt hadolint 2.15.1 and fix the four findings it rep…
cristim Aug 3, 2026
ef73202
fix(gcp): derive CUD commitment type from machine family (#1650)
cristim Aug 3, 2026
6d854c8
sec(iac/gcp): scope cleanup-function SA to the one secret it reads (#…
cristim Aug 3, 2026
890c47e
fix(arm): validate attribute mapping on GCP WIF provider reuse (#1673)
cristim Aug 3, 2026
34d85bc
sec(iac/gcp): pin WIF trust to the exact role ARN and narrow the SA g…
cristim Aug 3, 2026
802b4b1
fix(iac/aws): unblock deploy on rds:DescribeDBInstances and close aud…
cristim Aug 3, 2026
02702a1
fix(scheduler): withhold stale-row eviction after a partial sweep (#1…
cristim Aug 3, 2026
6427675
sec(iac/aws): require OIDC subject claim in the federation bundle gen…
cristim Aug 4, 2026
409a466
sec(iac): scope Azure purchase role to onboarded subscription (#1658)
cristim Aug 4, 2026
0c92b77
fix(ci): npm audit advisories and scanner decoupling in Security Scan…
cristim Aug 5, 2026
bba8576
fix(ci): stop interpolating the release tag into a run block (#1657)
cristim Aug 5, 2026
5526aab
fix(purchase): gate user-facing Retry on provider re-drive safety (#1…
cristim Aug 5, 2026
85a0b4b
fix(api): scope Azure exchangeable-RI listing to session's allowed ac…
cristim Aug 5, 2026
ff808b2
sec(iac/aws): gate deploy-role IAM writes on a permissions boundary (…
cristim Aug 6, 2026
9102e1c
chore(frontend): patch js-yaml and nanoid advisories (#1729)
cristim Aug 7, 2026
9b0b0bb
fix(scripts): add missing tfvars fields to generate-federation-iac.go…
cristim Aug 7, 2026
148c0ca
fix(ci): grant id-token permissions to deploy-all.yml caller jobs (#1…
cristim Aug 7, 2026
9145e0f
sec(ci): stop interpolating migration inputs into run blocks (#1726)
cristim Aug 7, 2026
c93724d
sec(frontend): escape payment field in plans and recs tables (#1727)
cristim Aug 8, 2026
0177350
fix(cli): apply --max-instances once run-wide, not per service and re…
cristim Aug 8, 2026
1a1e595
fix(test): make 78 unfailable MockConfigStore assertions able to fail…
cristim Aug 8, 2026
415b491
sec(frontend): stop group edit from dropping/widening permissions (#1…
cristim Aug 8, 2026
40800b8
fix(purchase): refuse to execute armed pre-#1668 retry successors (#1…
cristim Aug 8, 2026
e0fc45e
fix(frontend): pin formatCurrency to en-US instead of the host locale…
cristim Aug 8, 2026
d04cf31
fix(test): make grantAdmin model the principal instead of stubbing th…
cristim Aug 8, 2026
27355f3
ci: run unit and integration tests in every workspace module (#1755)
cristim Aug 8, 2026
1cd8c6f
sec(auth): fail closed when a user's account scope cannot be establis…
cristim Aug 8, 2026
9bfd682
sec(auth): carve execute:ri-exchange out of admin:* and seed the gran…
cristim Aug 8, 2026
87a853e
sec(auth): enforce a grant ceiling and system-managed guard on group …
cristim Aug 8, 2026
6d5275c
fix(test): repair 30 unfailable mock assertions and guard the class (…
cristim Aug 8, 2026
6df07bb
fix(test): stop using a carved-out verb as a generic ceiling fixture …
cristim Aug 8, 2026
88f16ec
refactor(auth): represent account scope as a type whose zero value de…
cristim Aug 8, 2026
29beea0
sec(api): scope ladder config writes to the caller's allowed_accounts…
cristim Aug 8, 2026
726389b
fix(azure): pair the recommended SKU with the count in its own units …
cristim Aug 8, 2026
d6e60f6
fix(azure): surface the read error that decides purchase retry-vs-abo…
cristim Aug 8, 2026
a37e147
docs(azure): correct two retry comments that #1767 made false (#1792)
cristim Aug 9, 2026
eca603a
sec(azure): re-check idempotency between in-process purchase retries …
cristim Aug 9, 2026
ea0578c
fix(ci/azure): name the missing bootstrap stack when the role lookup …
cristim Aug 10, 2026
fcdc681
sec(exchange): gate the config write that arms unattended RI exchange…
cristim Aug 10, 2026
ddeeb98
sec(api): enforce CSRF on the RI-exchange session-authed approve path…
cristim Aug 11, 2026
51e89a6
fix(iac/azure): remove nonexistent Microsoft.Capacity action from res…
cristim Aug 11, 2026
7b1ea4a
fix(iac/azure): stop replacing the reservation-purchaser role assignm…
cristim Aug 12, 2026
2c87db0
sec(auth): bound account scope on self-membership changes, both direc…
cristim Aug 12, 2026
8b16ed4
fix(ci/azure): serialize Terraform state writers on environment, not …
cristim Aug 12, 2026
17a568f
fix(ci): resolve deploy environment from inputs, not github.event_nam…
cristim Aug 12, 2026
bde563e
fix(ci): serialize AWS and GCP Terraform state writers on environment…
cristim Aug 13, 2026
23ad4e4
sec(api): bound plan and account scope on the plan-accounts endpoints…
cristim Aug 13, 2026
f458508
fix(api): submit-time idempotency for RI exchange execute (#1642)
cristim Aug 13, 2026
0145a32
fix(ci): add per-database concurrency groups to the database-migratio…
cristim Aug 13, 2026
929ee11
fix(ci): bump the pinned Go toolchain to 1.26.6 for stdlib CVE fixes …
cristim Aug 14, 2026
03cb133
sec(iac/aws): pin ecs, lambda and ssm per action in the deploy bounda…
cristim Aug 16, 2026
4c831be
sec(ci): select ECR repos to destroy by exact name, not substring (#1…
cristim Aug 17, 2026
15a42f0
sec(build): build the shipped image on go1.26.6, including the migrat…
cristim Aug 17, 2026
3a3ce20
fix(cli): enforce --min-count and savings-ordered capping on --input-…
cristim Aug 17, 2026
42c0943
fix(iac/azure): grant Key Vault access by RBAC role assignment, not a…
cristim Aug 18, 2026
5501419
fix(test): make a migration failure fail the integration suites, not …
cristim Aug 18, 2026
5108b13
sec(deps): bump go.opentelemetry.io/otel to v1.44.0 for GO-2026-5158
cristim Aug 18, 2026
6a2117c
sec(ci): scan the Go binaries in the shipped image, not just the sour…
cristim Aug 18, 2026
df05daa
sec(build): bump the runtime base to alpine:3.24.1 for fixable OS adv…
cristim Aug 18, 2026
560175e
fix(cli): rescale count-derived money when --max-instances truncates …
cristim Aug 18, 2026
4b2d54d
fix(cli): rescale count-derived money when --override-count replaces …
cristim Aug 18, 2026
71946d3
fix(ci): drop lib/pq by moving golang-migrate onto the pgx/v5 driver …
cristim Aug 18, 2026
4888fe8
sec(ci): delete only the ECR repo each staging state owns (#1848)
cristim Aug 18, 2026
9be12fc
sec(ci): unprotect only the RDS instance each state owns before destr…
cristim Aug 19, 2026
d9d1c13
test(api): cover retry-any:purchases carve-out at the retry handler (…
cristim Aug 19, 2026
48bae39
fix(frontend): resolve every route to its own page on direct load (#1…
cristim Aug 19, 2026
f8ed6bf
fix(ci): key rollback-aws-fargate on the Fargate Terraform state (#1857)
cristim Aug 19, 2026
b9f0d77
test(api): model the constraint dimension in MockAuthService (#1859)
cristim Aug 19, 2026
0d7a458
sec(scripts): constrain who the Azure onboarding template grants to (…
cristim Aug 19, 2026
7214c6b
fix(plans): make the ramp advance idempotent per step (#1862)
cristim Aug 19, 2026
034b86f
fix(frontend): render the Coverage bar column (#1864)
cristim Aug 19, 2026
fffd2ea
sec(iac): verify an existing GCP WIF provider instead of reusing it b…
cristim Aug 19, 2026
edb353c
fix(frontend): separate Upcoming Scheduled Purchases actions from the…
cristim Aug 19, 2026
c8bc76f
chore(ci): gate workflows on actionlint and zizmor (#1870)
cristim Aug 19, 2026
e583c0f
ci: bound the Playwright install and cache browsers (#1872)
cristim Aug 20, 2026
25fc19c
sec(frontend): preserve constraints.accounts through group edit (#1875)
cristim Aug 20, 2026
eeb6c7b
sec(iac/aws): pin cross-account sts:AssumeRole to declared account ID…
cristim Aug 20, 2026
ac00d9d
fix(frontend): move the topbar controls into the drawer below 768px (…
cristim Aug 20, 2026
ae1e632
fix(plans): count a ramp step only when every account has bought (#1880)
cristim Aug 23, 2026
84a884e
fix(cmd): match Savings Plans region filters on Details.Region (#1881)
cristim Aug 25, 2026
ae331a0
sec(deps): bump moby/go-archive to v0.3.0 for GO-2026-6253 (#1895)
cristim Aug 26, 2026
2905648
sec(deps): bump x/crypto to v0.55.0 for GO-2026-6303 (#1898)
cristim Aug 28, 2026
9050f6e
feat(mcp): annotate every tool with MCP ToolAnnotations (#1884)
cristim Aug 28, 2026
ad8c0a4
refactor(mcp): extract CLI filter/sizing/dedupe logic into pkg/recfil…
cristim Aug 29, 2026
dc510da
fix(mcp): inject build version into cudly-mcp and document Codex CLI …
cristim Aug 30, 2026
3c0f8ac
feat(mcp): add server.json for the MCP Registry + PR/tag validation C…
cristim Aug 31, 2026
fdf9c29
sec(deps): bump fast-uri and x/crypto to clear the three failing CI g…
cristim Sep 8, 2026
82a3c26
sec(auth): carve out money-verb wildcards at grant and check (#2069)
cristim Sep 8, 2026
aa26544
docs(audit): add the 2026-09-02 full codebase audit report (#1961)
cristim Sep 8, 2026
3bb33dd
fix(purchase): refuse a plan-less execution whose recs span cloud acc…
cristim Sep 8, 2026
8e44c0f
fix(api): derive the purchase spend cap from the stored recommendatio…
cristim Sep 8, 2026
1d4a628
fix(azure): error when the Retail Prices page cap is hit with pages r…
cristim Sep 8, 2026
eac9a62
fix(exchange): refuse a quote with no PaymentDue instead of treating …
cristim Sep 8, 2026
5405fd1
fix(deps): patch js-yaml and svgo audit advisories (#2090)
cristim Sep 11, 2026
596680d
fix(frontend): re-price purchase modal rows and stop submitting skipp…
cristim Sep 14, 2026
81f2fc3
sec(ci): delete only the Cloud SQL instance the staging state owns (#…
cristim Sep 14, 2026
efd6e95
fix(iac/aws): grant six required runtime CE and EC2 actions (#2077)
cristim Sep 14, 2026
6f6991c
fix(frontend): reprice complete fan-out purchase variants
cristim Sep 14, 2026
6932db9
fix(frontend): keep fan-out selection and submission consistent
cristim Sep 14, 2026
a730239
fix(frontend): clarify unused fan-out bucket payment default
cristim Sep 14, 2026
b14df7e
Merge pull request #2094 from LeanerCloud/fix/2070-fanout-payment-rep…
cristim Sep 15, 2026
7c5df37
feat(mcp): JSONL purchase audit log, on by default
cristim Aug 25, 2026
a44cec1
fix(common): reject non-regular audit log targets
cristim Aug 28, 2026
3d04da0
fix(common): durably append audit records
cristim Aug 28, 2026
d637e15
docs(mcp): distinguish stderr and JSONL audit trails
cristim Aug 29, 2026
98be06a
docs(mcp): qualify preview audit warning comments
cristim Aug 29, 2026
faa91ca
fix(common): terminate partial audit JSONL writes
cristim Aug 29, 2026
33ffb4d
test(mcp): isolate command audit log path
cristim Aug 29, 2026
7ed77f2
fix(mcp): classify errored purchase results
cristim Aug 29, 2026
af825e9
fix(common): lock audit append transactions
cristim Aug 29, 2026
ecdecf9
fix(aws): record audit lock dependency
cristim Aug 29, 2026
fdb4ae7
docs(mcp): clarify preview audit behavior
cristim Aug 29, 2026
6477471
docs(mcp): qualify audit persistence
cristim Aug 30, 2026
c45b0a0
fix(mcp): record audit credential scope
cristim Aug 30, 2026
217b0be
test(common): relax audit helper timeout
cristim Aug 30, 2026
99b65ef
fix(common): repair abandoned audit log tails
cristim Aug 30, 2026
2ce74b7
test: consolidate duplicate audit coverage
cristim Aug 30, 2026
e6a28e0
docs(mcp): qualify dry-run audit persistence
cristim Aug 30, 2026
46b5bd3
fix(mcp): persist provider failure audit reason
cristim Aug 30, 2026
e685112
fix(mcp): persist audit log directory entries
cristim Aug 30, 2026
85440c2
fix(audit): validate Unix descriptor conversions
cristim Aug 30, 2026
15e610f
fix(lint): exempt established common package name
cristim Aug 30, 2026
1531e23
test(mcp): report audit setup failures clearly
cristim Aug 30, 2026
bb38067
feat(mcp): declare audit log registry setting
cristim Aug 31, 2026
7eb107c
fix(mcp): keep preview audit scope explicit
cristim Sep 2, 2026
9f776b9
fix(common): bound audit log lock acquisition
cristim Sep 2, 2026
2b03108
test(audit): cover lock timeout consumers
cristim Sep 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
49 changes: 49 additions & 0 deletions .air.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Air configuration for hot reload in development
# https://github.com/air-verse/air

root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ./cmd/server"
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "frontend", "node_modules"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false

[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"

[log]
main_only = false
time = false

[misc]
clean_on_exit = false

[screen]
clear_on_rebuild = false
keep_scroll = true
3 changes: 3 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
reviews:
path_filters:
- '**/package-lock.json'
39 changes: 39 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Terraform state and providers
**/.terraform
*.tfstate
*.tfstate.backup
*.tfbackend

# Frontend build artifacts and dependencies
frontend/node_modules
frontend/coverage
frontend/dist

# IDE and OS
.idea
.vscode
.DS_Store

# Git
.git

# Go vendor (dependencies downloaded at build time)
vendor/

# Temporary files
tmp/

# Docker compose dev files
docker-compose.yml
Dockerfile.dev

# Secrets and credentials
.env
.env.*
*.pem
*.key
*.p12
credentials/
*.tfstate
*.tfstate.backup
.terraform/
123 changes: 123 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# CUDly local development env template
#
# Copy this file to `.env.local` (already in .gitignore) and fill in
# the placeholders. Loaded by: load-env.sh / your IDE / `direnv` —
# CUDly itself reads these via os.Getenv at runtime.
#
# All values here are PLACEHOLDERS. Never commit real secrets to .env*
# files; the .gitignore at the repo root already excludes everything
# matching `.env*` except this template.

# ---------------------------------------------------------------------
# Required: secrets resolver
# ---------------------------------------------------------------------
# SECRET_PROVIDER selects which secret store the resolver fetches from.
# aws | gcp | azure — production: real Secrets Manager / Key Vault
# env — local dev: resolve secret names to env vars
# In `env` mode, every secret-ref var (ADMIN_PASSWORD_SECRET,
# API_KEY_SECRET_ARN, etc.) holds the NAME of another env var whose
# value is the actual secret. See `internal/secrets/env_resolver.go`.
# Pairs with EMAIL_ENABLED=false so the email factory's no-op sender
# kicks in (see PR #333) — otherwise `env` is not a recognised email
# backend and the factory would fail dispatch.
SECRET_PROVIDER=env

# ---------------------------------------------------------------------
# Required: scheduled-task auth mode (no default — must be explicit)
# ---------------------------------------------------------------------
# Selects how the internal /api/scheduled/* endpoints authenticate.
# oidc — production: verify Google-issued OIDC ID tokens
# bearer — shared-secret token in Authorization header
# disabled — local dev: no auth check
# Required by `internal/server/scheduledauth/config.go`; app refuses
# to start when unset.
SCHEDULED_TASK_AUTH_MODE=disabled

# ---------------------------------------------------------------------
# Required: email gate (factory short-circuit, see PR #333)
# ---------------------------------------------------------------------
# When `false`, internal/email/factory.go returns a no-op sender that
# logs each invocation at debug level instead of dispatching to a
# cloud-specific backend. Pair with SECRET_PROVIDER=env for local dev.
EMAIL_ENABLED=false

# ---------------------------------------------------------------------
# Required: credential encryption key
# ---------------------------------------------------------------------
# In production exactly ONE of the per-cloud secret refs is set; the
# Go side reads them in priority order (ARN → NAME → ID → raw KEY).
# For local dev set CREDENTIAL_ENCRYPTION_ALLOW_DEV_KEY=1 to use the
# all-zero dev key without touching a Secrets Manager / Key Vault.
CREDENTIAL_ENCRYPTION_ALLOW_DEV_KEY=1

# CREDENTIAL_ENCRYPTION_KEY_SECRET_ARN=arn:aws:secretsmanager:us-east-1:000000000000:secret:cudly-cred-enc-key-PLACEHOLDER
# CREDENTIAL_ENCRYPTION_KEY_SECRET_NAME=cudly-credential-encryption-key
# CREDENTIAL_ENCRYPTION_KEY_SECRET_ID=cudly-credential-encryption-key
# CREDENTIAL_ENCRYPTION_KEY=<64-hex-chars>

# ---------------------------------------------------------------------
# Required: admin auth + API
# ---------------------------------------------------------------------
# With SECRET_PROVIDER=env, the *_SECRET / *_SECRET_ARN vars hold the
# NAME of another env var whose value is the actual secret. The matched
# env var must then be defined below. Two reasons for the indirection:
# (1) production uses the same var name pointing at a real ARN/name;
# (2) the dev value is co-located with its lookup key so future readers
# can trace the chain in one file.
ADMIN_EMAIL=admin@cudly.local
ADMIN_PASSWORD_SECRET=ADMIN_PASSWORD_DEV
ADMIN_PASSWORD_DEV=LocalDev!Pass123
API_KEY_SECRET_ARN=ADMIN_API_KEY_DEV
ADMIN_API_KEY_DEV=cudly-local-dev-api-key-not-for-prod
# Required for signed one-click notification unsubscribe links. Generate a
# unique value for every environment (for example: openssl rand -hex 32).
NOTIFICATION_MUTE_SECRET=
# Production examples (override SECRET_PROVIDER and these):
# ADMIN_PASSWORD_SECRET=arn:aws:secretsmanager:us-east-1:000000000000:secret:cudly-admin-password-PLACEHOLDER
# API_KEY_SECRET_ARN=arn:aws:secretsmanager:us-east-1:000000000000:secret:cudly-api-key-PLACEHOLDER

# ---------------------------------------------------------------------
# Optional: web frontend / CORS / dashboard
# ---------------------------------------------------------------------
CORS_ALLOWED_ORIGIN=http://localhost:3000
DASHBOARD_URL=http://localhost:3000
# ENABLE_DASHBOARD=true
# DASHBOARD_BUCKET=cudly-dashboard-PLACEHOLDER

# ---------------------------------------------------------------------
# Optional: PostgreSQL (lazy — unset to skip)
# ---------------------------------------------------------------------
# DB_HOST=localhost
# DB_PORT=5432
# DB_USER=cudly
# DB_NAME=cudly
# DB_PASSWORD_SECRET=arn:aws:secretsmanager:us-east-1:000000000000:secret:cudly-db-PLACEHOLDER
# CUDLY_MIGRATION_TIMEOUT=2m

# ---------------------------------------------------------------------
# Optional: cloud-provider profiles for multi-cloud onboarding
# ---------------------------------------------------------------------
# AWS_CONFIG_FILE=$HOME/.aws/config
# AZURE_TENANT_ID=00000000-0000-0000-0000-000000000000
# AZURE_CLIENT_ID=00000000-0000-0000-0000-000000000000
# AZURE_SUBSCRIPTION_ID=00000000-0000-0000-0000-000000000000
# AZURE_KEY_VAULT_URL=https://cudly-vault-placeholder.vault.azure.net/
# GCP_PROJECT_ID=cudly-placeholder
# AWS_REGION=us-east-1

# ---------------------------------------------------------------------
# Optional: SES / Azure ACS / SendGrid email config
# ---------------------------------------------------------------------
# EMAIL_ADDRESS=noreply@cudly.example
# AZURE_SMTP_HOST=smtp.azurecomm.net
# AZURE_SMTP_USERNAME_SECRET=arn:aws:secretsmanager:us-east-1:000000000000:secret:cudly-smtp-user-PLACEHOLDER
# AZURE_SMTP_PASSWORD_SECRET=arn:aws:secretsmanager:us-east-1:000000000000:secret:cudly-smtp-pass-PLACEHOLDER

# ---------------------------------------------------------------------
# Optional: tunables
# ---------------------------------------------------------------------
# CUDLY_RECOMMENDATION_CACHE_TTL=15m
# CUDLY_MAX_ACCOUNT_PARALLELISM=8
# DEFAULT_PAYMENT_OPTION=no-upfront
# DEFAULT_RAMP_SCHEDULE=quarterly
# ENVIRONMENT=local
48 changes: 48 additions & 0 deletions .gitallowed
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# git-secrets allowlist: regexes that should NOT trigger the AWS-secret scanner.
#
# The scanner's `--register-aws` adds a 12-digit account-ID pattern that
# matches our test fixtures. The values below are obvious test placeholders
# (sequential 123456789012, all-same-digit blocks like 111111111111, and
# countdown patterns like 999888777666) — chosen specifically because they
# cannot be real customer accounts. Adding these is safer than disabling the
# AWS-account check entirely.
#
# DO NOT add a real account ID here. If a real account ID lands in the repo,
# rotate it and treat the leak seriously instead of silencing the scanner.
#
# Format: one regex per line, matched against each line of file content
# (path-scoping is not supported by .gitallowed).

# Sequential test placeholders (ascending and descending).
123456789012
210987654321

# All-same-digit blocks of 12 — used as table-row distinctions in fixtures.
# Listed explicitly rather than via a regex back-reference because not every
# git-secrets build supports back-refs in its allowlist regexes.
000000000000
111111111111
222222222222
333333333333
444444444444
555555555555
666666666666
777777777777
888888888888
999999999999

# Group-block placeholders used in cmd/helpers_test.go variants and
# cmd/multi_service_helpers_test.go.
111222333444
555666777888
999888777666
# Descending-step fixture added in #956 tests (store_postgres_pgxmock_test.go,
# handler_analytics_test.go, handler_history_test.go, handler_dashboard_test.go).
999988887777
# Repeating-pair-block fixture used in handler_analytics_test.go,
# handler_inventory_test.go, store_postgres_pgxmock_test.go.
111122223333

# UUID-shaped account ID used in handler_accounts_test.go (synthetic, not a
# real subscription/account).
11111111-1111-1111-1111-111111111111
Loading
Loading