Compare commits

...

121 Commits

Author SHA1 Message Date
public-glueops-renovatebot[bot]
ddb6f555c0 chore(lockfile): update motion-lockfile #patch 2026-02-11 20:21:31 +00:00
public-glueops-renovatebot[bot]
a40da0c23d chore(patch): update @types/react to 19.2.13 #patch (#650)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-11 20:04:26 +00:00
public-glueops-renovatebot[bot]
1c740da56d chore(patch): update @types/node to 25.2.2 #patch (#652)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-11 06:00:17 +00:00
public-glueops-renovatebot[bot]
0136c8ef78 chore(patch): update shadcn to 3.8.3 #patch (#642)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-07 17:45:19 +00:00
public-glueops-renovatebot[bot]
d4fdd85671 chore(patch): update @types/react to 19.2.11 #patch (#645)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-07 15:00:28 +00:00
public-glueops-renovatebot[bot]
5d3f0bfaf6 chore: lock file maintenance (#624)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:06:43 +00:00
public-glueops-renovatebot[bot]
3926bafa5c feat: update docker/login-action to v3.7.0 #minor (#623)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:03:13 +00:00
public-glueops-renovatebot[bot]
210a056fe6 feat: update github.com/aws/aws-sdk-go-v2/service/s3 to v1.96.0 #minor (#627)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:03:00 +00:00
public-glueops-renovatebot[bot]
b864187af5 feat: update typescript-eslint to 8.54.0 #minor (#618)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:02:44 +00:00
public-glueops-renovatebot[bot]
10725d9263 chore(lockfile): update motion-lockfile #patch (#633)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:02:30 +00:00
public-glueops-renovatebot[bot]
84d5575ea8 feat: update eslint-plugin-react-refresh to 0.5.0 #minor (#629)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:02:23 +00:00
public-glueops-renovatebot[bot]
b7b2c3c65d chore(patch): update motion to 12.29.3 #patch (#632)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:02:13 +00:00
public-glueops-renovatebot[bot]
94cd1ca2df chore(patch): update github.com/golang-jwt/jwt/v5 to v5.3.1 #patch (#626)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:01:59 +00:00
public-glueops-renovatebot[bot]
9379e8dd05 chore(patch): update golang to 1.25.7 #patch (#639)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:01:48 +00:00
public-glueops-renovatebot[bot]
e0b15f6b9e chore(patch): update github.com/go-chi/chi/v5 to v5.2.5 #patch (#641)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:01:42 +00:00
public-glueops-renovatebot[bot]
accf590d24 chore(patch): update @vitejs/plugin-react to 5.1.3 #patch (#631)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 23:01:21 +00:00
public-glueops-renovatebot[bot]
b910ff52ab feat: update @types/node to 25.2.1 #minor (#630)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 22:48:50 +00:00
public-glueops-renovatebot[bot]
1e498b309b chore(patch): update @types/react to 19.2.10 #patch (#619)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 22:40:45 +00:00
public-glueops-renovatebot[bot]
85601bcb84 chore(patch): update shadcn to 3.8.2 #patch (#635)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-05 11:32:21 +00:00
public-glueops-renovatebot[bot]
ce348a65ea chore(patch): update shadcn to 3.8.1 #patch (#634)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-03 11:59:38 +00:00
public-glueops-renovatebot[bot]
37153a6eed feat: update shadcn to 3.8.0 #minor (#628)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-02-03 00:52:13 +00:00
public-glueops-renovatebot[bot]
936891d110 chore(patch): update typescript-eslint to 8.53.1 #patch (#608)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:49:07 +00:00
public-glueops-renovatebot[bot]
965a5ed88b chore: lock file maintenance (#620)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:23:14 +00:00
public-glueops-renovatebot[bot]
c2b76f1dea chore(patch): update prettier to 3.8.1 #patch (#611)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:22:37 +00:00
public-glueops-renovatebot[bot]
5c9768b0b2 chore(patch): update @tanstack/react-query to 5.90.20 #patch (#598)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:22:22 +00:00
public-glueops-renovatebot[bot]
a02c29f333 chore(fallback): update golang (#607)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:22:16 +00:00
public-glueops-renovatebot[bot]
223d89bdd1 chore(patch): update @types/node to 25.0.10 #patch (#613)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:22:09 +00:00
public-glueops-renovatebot[bot]
411c98174a chore(lockfile): update motion-lockfile #patch (#614)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:22:03 +00:00
public-glueops-renovatebot[bot]
a7657368ed chore: lock file maintenance (#605)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:21:14 +00:00
public-glueops-renovatebot[bot]
134153c197 feat: update shadcn to 3.7.0 #minor (#603)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:20:44 +00:00
public-glueops-renovatebot[bot]
b4905b8c59 feat: update lucide-react to 0.563.0 #minor (#616)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:20:23 +00:00
public-glueops-renovatebot[bot]
f9dc0d4db5 chore(lockfile): update react-router-dom-lockfile #patch (#617)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:20:11 +00:00
public-glueops-renovatebot[bot]
3d6e53d24d chore(lockfile): update motion-lockfile #patch (#610)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:19:38 +00:00
public-glueops-renovatebot[bot]
2f6a382733 chore(lockfile): update motion-lockfile #patch (#606)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:19:27 +00:00
public-glueops-renovatebot[bot]
8261b5d702 chore(patch): update @types/react to 19.2.9 #patch (#609)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-27 18:01:27 +00:00
public-glueops-renovatebot[bot]
23415ead6d chore(patch): update @types/node to 25.0.9 #patch (#604)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-22 01:15:32 +00:00
public-glueops-renovatebot[bot]
ba8098acac feat: update prettier to 3.8.0 #minor (#600)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-21 18:51:23 +00:00
public-glueops-renovatebot[bot]
da5801cc6b chore: lock file maintenance (#596)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-16 17:33:44 +00:00
public-glueops-renovatebot[bot]
809c0930ae chore(patch): update golang to 1.25.6 #patch (#601)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-16 17:33:10 +00:00
public-glueops-renovatebot[bot]
17af4e8da4 chore(patch): update motion to 12.26.2 #patch (#592)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-16 17:33:05 +00:00
public-glueops-renovatebot[bot]
039fb04c97 chore(patch): update github.com/go-chi/chi/v5 to v5.2.4 #patch (#599)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-16 17:32:52 +00:00
public-glueops-renovatebot[bot]
335fd10fab chore(patch): update @types/react to 19.2.8 #patch (#590)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-16 17:32:43 +00:00
public-glueops-renovatebot[bot]
a3ec862e12 feat: update typescript-eslint to 8.53.0 #minor (#594)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-16 17:31:14 +00:00
public-glueops-renovatebot[bot]
66595daa4b chore(patch): update @types/node to 25.0.8 #patch (#602)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-16 17:16:31 +00:00
public-glueops-renovatebot[bot]
d6d1806907 chore(patch): update @types/node to 25.0.7 #patch (#597)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-16 08:30:02 +00:00
public-glueops-renovatebot[bot]
3c61f66c9a chore(patch): update @types/node to 25.0.6 #patch (#595)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-13 18:14:04 +00:00
public-glueops-renovatebot[bot]
0fb6fa3389 feat: update golang.org/x/crypto to v0.47.0 #minor (#593)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-13 04:35:28 +00:00
public-glueops-renovatebot[bot]
4cd9f77694 chore(patch): update github.com/aws/aws-sdk-go-v2 to v1.41.1 #patch (#588)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-13 04:23:26 +00:00
public-glueops-renovatebot[bot]
f6af0d970f chore(patch): update vite to 7.3.1 #patch (#578)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-13 04:02:47 +00:00
public-glueops-renovatebot[bot]
1138b346e3 chore: lock file maintenance (#587)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-13 04:02:17 +00:00
public-glueops-renovatebot[bot]
4e612652a2 chore(patch): update @types/node to 25.0.5 #patch (#589)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-13 03:24:39 +00:00
public-glueops-renovatebot[bot]
4127c0dd06 chore: lock file maintenance (#586)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-09 10:45:20 +00:00
public-glueops-renovatebot[bot]
8e97df134a chore(patch): update github.com/swaggo/swag/v2 to v2.0.0-rc5 #patch (#584)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-09 10:44:46 +00:00
public-glueops-renovatebot[bot]
636b500108 chore(patch): update shadcn to 3.6.3 #patch (#572)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-09 10:43:54 +00:00
public-glueops-renovatebot[bot]
2e3fd44b34 chore: lock file maintenance (#583)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-08 18:28:09 +00:00
public-glueops-renovatebot[bot]
2bfd8b0a78 chore: lock file maintenance (#581)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-08 17:14:27 +00:00
public-glueops-renovatebot[bot]
c7fb0bcf18 feat: update typescript-eslint to 8.52.0 #minor (#570)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-08 17:13:05 +00:00
public-glueops-renovatebot[bot]
c4a0fbd7b8 chore: lock file maintenance (#580)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-07 09:46:32 +00:00
public-glueops-renovatebot[bot]
8616336279 chore: lock file maintenance (#579)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-07 09:45:20 +00:00
public-glueops-renovatebot[bot]
d1ea3667e6 chore: lock file maintenance (#577)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-06 17:29:30 +00:00
allanice001
0f562ac5f4 ui fixes 2026-01-06 17:05:52 +00:00
allanice001
810218124e revert, but increase httprate 2026-01-06 10:11:42 +00:00
allanice001
5aff256377 fix import issue 2026-01-06 09:59:23 +00:00
Alanis
bdd6b61859 Remove rate limiting by IP from routes
Removed rate limiting middleware from the API routes.
2026-01-06 09:50:10 +00:00
public-glueops-renovatebot[bot]
42a86b22dd chore: lock file maintenance (#567)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-05 10:45:19 +00:00
public-glueops-renovatebot[bot]
b8cb1e1a2a chore: lock file maintenance (#566)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-05 10:11:13 +00:00
public-glueops-renovatebot[bot]
5a4ae19900 chore: lock file maintenance (#564)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-04 10:51:50 +00:00
public-glueops-renovatebot[bot]
d9db293894 chore: lock file maintenance (#563)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-04 08:27:53 +00:00
public-glueops-renovatebot[bot]
19d5ee7251 chore: lock file maintenance (#562)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-04 04:12:39 +00:00
public-glueops-renovatebot[bot]
6b91a5760b chore: lock file maintenance (#560)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-03 13:32:05 +00:00
public-glueops-renovatebot[bot]
bbd4c86013 chore: lock file maintenance (#559)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-02 14:40:46 +00:00
public-glueops-renovatebot[bot]
99ebcb11a3 chore: lock file maintenance (#558)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-02 13:44:37 +00:00
public-glueops-renovatebot[bot]
be1b35da3c feat: update typescript-eslint to 8.51.0 #minor (#540)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2026-01-01 17:09:21 +00:00
public-glueops-renovatebot[bot]
a6a296f283 chore: lock file maintenance (#556)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-31 23:27:07 +00:00
public-glueops-renovatebot[bot]
341ecf8b0a chore: lock file maintenance (#555)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-31 19:37:14 +00:00
public-glueops-renovatebot[bot]
92998015ec chore: lock file maintenance (#554)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-31 16:10:12 +00:00
public-glueops-renovatebot[bot]
9345c2761c chore: lock file maintenance (#553)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-31 15:08:55 +00:00
public-glueops-renovatebot[bot]
6944e5d027 chore: lock file maintenance (#552)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-31 06:14:14 +00:00
public-glueops-renovatebot[bot]
48b3bf5d3c chore: lock file maintenance (#551)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-31 06:13:11 +00:00
public-glueops-renovatebot[bot]
4c595db85e chore: lock file maintenance (#550)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-31 05:42:43 +00:00
allanice001
79f3259bd6 fix: ensure only a single instance is fired
Signed-off-by: allanice001 <allanice001@gmail.com>
2025-12-30 17:30:38 +00:00
allanice001
e0d163181a Merge branch 'main' of github.com:GlueOps/autoglue 2025-12-30 16:35:18 +00:00
allanice001
e8d568eba7 fix: ensure only a single instance is fired
Signed-off-by: allanice001 <allanice001@gmail.com>
2025-12-30 16:35:00 +00:00
public-glueops-renovatebot[bot]
c21a766dab chore: lock file maintenance (#548)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-30 15:09:36 +00:00
public-glueops-renovatebot[bot]
495c1551b4 chore: lock file maintenance (#547)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-30 08:45:47 +00:00
public-glueops-renovatebot[bot]
4a5c0df481 chore: lock file maintenance (#545)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 22:09:22 +00:00
public-glueops-renovatebot[bot]
c92bba5518 chore: lock file maintenance (#544)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 22:08:16 +00:00
public-glueops-renovatebot[bot]
823088e294 chore: lock file maintenance (#543)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 19:52:02 +00:00
public-glueops-renovatebot[bot]
938689fda3 chore: lock file maintenance (#542)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 18:46:56 +00:00
public-glueops-renovatebot[bot]
77332f208f chore: lock file maintenance (#541)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 17:26:24 +00:00
public-glueops-renovatebot[bot]
711488492c breaking: the dependency actions/checkout has been updated to a new major version (v6), which may include breaking changes. #major (#536)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 17:03:09 +00:00
public-glueops-renovatebot[bot]
27b89722a4 chore: lock file maintenance (#539)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 16:27:51 +00:00
public-glueops-renovatebot[bot]
c8a537e30f chore(fallback): update postgres (#535)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 12:34:44 +00:00
public-glueops-renovatebot[bot]
98de70b96b chore: lock file maintenance (#538)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 12:34:10 +00:00
public-glueops-renovatebot[bot]
63c4574f9c chore(fallback): update axllent/mailpit (#534)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 12:33:13 +00:00
public-glueops-renovatebot[bot]
5e85cad5b7 chore(pin): update typescript to #patch (#533)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-29 12:32:35 +00:00
allanice001
53725bb834 chore: add org id to org table 2025-12-29 11:59:27 +00:00
public-glueops-renovatebot[bot]
6611dc4950 chore(patch): update typescript-eslint to 8.50.1 #patch (#511)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-28 01:26:48 +00:00
public-glueops-renovatebot[bot]
49665ffc9c feat: update github.com/aws/aws-sdk-go-v2/service/s3 to v1.95.0 #minor (#516)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-28 01:26:33 +00:00
public-glueops-renovatebot[bot]
ac14ef8fff chore: lock file maintenance (#528)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-28 01:25:13 +00:00
allanice001
f8e543b595 fix: improve dns error logging 2025-12-28 00:08:42 +00:00
allanice001
8cc81e52b7 fix: add get record for dns 2025-12-27 23:21:59 +00:00
public-glueops-renovatebot[bot]
d6e28c7fa2 chore(patch): update @types/node to 25.0.3 #patch (#507)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 15:30:04 +00:00
public-glueops-renovatebot[bot]
9832229194 chore(patch): update eslint-plugin-react-refresh to 0.4.26 #patch (#508)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 15:29:07 +00:00
public-glueops-renovatebot[bot]
da82998754 chore(fallback): update alpine (#487)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 15:28:34 +00:00
public-glueops-renovatebot[bot]
bca32fe784 chore(fallback): update golang (#486)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 15:28:18 +00:00
public-glueops-renovatebot[bot]
848e8d5179 chore(patch): update shadcn to 3.6.2 #patch (#510)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 15:28:03 +00:00
public-glueops-renovatebot[bot]
d3ee38881c feat: update docker/setup-buildx-action to v3.12.0 #minor (#515)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 15:27:20 +00:00
public-glueops-renovatebot[bot]
d39db44aa7 feat: update lucide-react to 0.562.0 #minor (#518)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 15:26:54 +00:00
public-glueops-renovatebot[bot]
01b29a4706 feat: update vite to 7.3.0 #minor (#519)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 15:26:38 +00:00
allanice001
bc3bd92d54 fix: improve job tracking
Signed-off-by: allanice001 <allanice001@gmail.com>
2025-12-26 15:14:48 +00:00
allanice001
2057f92b82 fix: improve job tracking 2025-12-26 15:04:31 +00:00
allanice001
169283b6c7 fix: improve job tracking
Signed-off-by: allanice001 <allanice001@gmail.com>
2025-12-26 15:04:15 +00:00
allanice001
865270312c fix: update jobs
Signed-off-by: allanice001 <allanice001@gmail.com>
2025-12-26 04:47:08 +00:00
public-glueops-renovatebot[bot]
7cc447c0f5 chore(lockfile): update react-hook-form-lockfile #patch (#496)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 01:12:10 +00:00
public-glueops-renovatebot[bot]
8a0345f7f5 chore: lock file maintenance (#520)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 01:11:47 +00:00
public-glueops-renovatebot[bot]
bb7114efe9 feat: update github.com/go-playground/validator/v10 to v10.30.1 #minor (#517)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 00:45:14 +00:00
public-glueops-renovatebot[bot]
9dd0148764 chore(lockfile): update react-router-dom-lockfile #patch (#514)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 00:45:00 +00:00
public-glueops-renovatebot[bot]
bcc69e1c86 chore(lockfile): update react-day-picker-lockfile #patch (#513)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 00:44:27 +00:00
public-glueops-renovatebot[bot]
a7bf6b43b4 chore(patch): update zod to 4.2.1 #patch (#512)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 00:44:17 +00:00
public-glueops-renovatebot[bot]
ced0a0663f chore(patch): update github.com/aws/aws-sdk-go-v2/config to v1.32.6 #patch (#509)
Co-authored-by: public-glueops-renovatebot[bot] <186083205+public-glueops-renovatebot[bot]@users.noreply.github.com>
2025-12-26 00:43:51 +00:00
43 changed files with 6007 additions and 5355 deletions

View File

@@ -33,7 +33,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
# Install the cosign tool except on PR # Install the cosign tool except on PR
# https://github.com/sigstore/cosign-installer # https://github.com/sigstore/cosign-installer
@@ -47,13 +47,13 @@ jobs:
# multi-platform images and export cache # multi-platform images and export cache
# https://github.com/docker/setup-buildx-action # https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
# Login against a Docker registry except on PR # Login against a Docker registry except on PR
# https://github.com/docker/login-action # https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }} - name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}

View File

@@ -1,7 +1,7 @@
################################# #################################
# Builder: Go + Node in one # Builder: Go + Node in one
################################# #################################
FROM golang:1.25.5-alpine@sha256:26111811bc967321e7b6f852e914d14bede324cd1accb7f81811929a6a57fea9 AS builder FROM golang:1.25.7-alpine@sha256:81d49e1de26fa223b9ae0b4d5a4065ff8176a7d80aa5ef0bd9f2eee430afe4d7 AS builder
RUN apk add --no-cache \ RUN apk add --no-cache \
bash git ca-certificates tzdata \ bash git ca-certificates tzdata \
@@ -24,7 +24,7 @@ RUN make build
################################# #################################
# Runtime # Runtime
################################# #################################
FROM alpine:3.23@sha256:51183f2cfa6320055da30872f211093f9ff1d3cf06f39a0bdb212314c5dc7375 FROM alpine:3.23@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62
RUN apk add --no-cache ca-certificates tzdata postgresql17-client \ RUN apk add --no-cache ca-certificates tzdata postgresql17-client \
&& addgroup -S app && adduser -S app -G app && addgroup -S app && adduser -S app -G app

View File

@@ -15,7 +15,7 @@ services:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data
mailpit: mailpit:
image: axllent/mailpit@sha256:e22dce5b36f93c77082e204a3942fb6b283b7896e057458400a4c88344c3df68 image: axllent/mailpit@sha256:c076638db1e15662150be4fb62b8a6e96ef6ba5bde90c838a0239225854830f7
restart: always restart: always
ports: ports:
- "1025:1025" - "1025:1025"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4164,6 +4164,42 @@ paths:
external deletion policy) external deletion policy)
tags: tags:
- DNS - DNS
get:
operationId: GetRecordSet
parameters:
- description: Organization UUID
in: header
name: X-Org-ID
schema:
type: string
- description: Record Set ID (UUID)
in: path
name: id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/dto.RecordSetResponse'
description: OK
"403":
content:
application/json:
schema:
type: string
description: organization required
"404":
content:
application/json:
schema:
type: string
description: not found
summary: Get a record set (org scoped)
tags:
- DNS
patch: patch:
operationId: UpdateRecordSet operationId: UpdateRecordSet
parameters: parameters:

58
go.mod
View File

@@ -4,28 +4,29 @@ go 1.25.4
require ( require (
github.com/alexedwards/argon2id v1.0.0 github.com/alexedwards/argon2id v1.0.0
github.com/aws/aws-sdk-go-v2 v1.41.0 github.com/aws/aws-sdk-go-v2 v1.41.1
github.com/aws/aws-sdk-go-v2/config v1.32.5 github.com/aws/aws-sdk-go-v2/config v1.32.7
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 github.com/aws/aws-sdk-go-v2/credentials v1.19.7
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0 github.com/aws/aws-sdk-go-v2/service/route53 v1.62.1
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0 github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0
github.com/aws/smithy-go v1.24.0
github.com/coreos/go-oidc/v3 v3.17.0 github.com/coreos/go-oidc/v3 v3.17.0
github.com/dyaksa/archer v1.1.5 github.com/dyaksa/archer v1.1.5
github.com/fergusstrange/embedded-postgres v1.33.0 github.com/fergusstrange/embedded-postgres v1.33.0
github.com/gin-gonic/gin v1.11.0 github.com/gin-gonic/gin v1.11.0
github.com/go-chi/chi/v5 v5.2.3 github.com/go-chi/chi/v5 v5.2.5
github.com/go-chi/cors v1.2.2 github.com/go-chi/cors v1.2.2
github.com/go-chi/httprate v0.15.0 github.com/go-chi/httprate v0.15.0
github.com/go-playground/validator/v10 v10.29.0 github.com/go-playground/validator/v10 v10.30.1
github.com/golang-jwt/jwt/v5 v5.3.0 github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/rs/zerolog v1.34.0 github.com/rs/zerolog v1.34.0
github.com/sosedoff/pgweb v0.17.0 github.com/sosedoff/pgweb v0.17.0
github.com/spf13/cobra v1.10.2 github.com/spf13/cobra v1.10.2
github.com/spf13/viper v1.21.0 github.com/spf13/viper v1.21.0
github.com/swaggo/swag/v2 v2.0.0-rc4 github.com/swaggo/swag/v2 v2.0.0-rc5
golang.org/x/crypto v0.46.0 golang.org/x/crypto v0.47.0
golang.org/x/oauth2 v0.34.0 golang.org/x/oauth2 v0.34.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/datatypes v1.2.7 gorm.io/datatypes v1.2.7
@@ -39,20 +40,19 @@ require (
github.com/KyleBanks/depth v1.2.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect
github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 // indirect github.com/ScaleFT/sshkeys v0.0.0-20200327173127-6142f742bca5 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.14.0 // indirect github.com/bytedance/sonic v1.14.0 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/bytedance/sonic/loader v0.3.0 // indirect
@@ -61,7 +61,7 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.11 // indirect github.com/gabriel-vasile/mimetype v1.4.12 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
@@ -113,7 +113,7 @@ require (
github.com/spf13/cast v1.10.0 // indirect github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/pflag v1.0.10 // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/sv-tools/openapi v0.2.1 // indirect github.com/sv-tools/openapi v0.4.0 // indirect
github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948 // indirect github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.0 // indirect github.com/ugorji/go/codec v1.3.0 // indirect
@@ -122,12 +122,12 @@ require (
go.uber.org/mock v0.5.0 // indirect go.uber.org/mock v0.5.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.20.0 // indirect golang.org/x/arch v0.20.0 // indirect
golang.org/x/mod v0.30.0 // indirect golang.org/x/mod v0.31.0 // indirect
golang.org/x/net v0.47.0 // indirect golang.org/x/net v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.32.0 // indirect golang.org/x/text v0.33.0 // indirect
golang.org/x/tools v0.39.0 // indirect golang.org/x/tools v0.40.0 // indirect
google.golang.org/protobuf v1.36.9 // indirect google.golang.org/protobuf v1.36.9 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.5.7 // indirect gorm.io/driver/mysql v1.5.7 // indirect

86
go.sum
View File

@@ -12,44 +12,76 @@ github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHc
github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw= github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw=
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.5 h1:pz3duhAfUgnxbtVhIK39PGF/AHYyrzGEyRD9Og0QrE8= github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8=
github.com/aws/aws-sdk-go-v2/config v1.32.5/go.mod h1:xmDjzSUs/d0BB7ClzYPAZMmgQdrodNjPPhd6bGASwoE= github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI=
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 h1:xMo63RlqP3ZZydpJDMBsH9uJ10hgHYfQFIk1cHDXrR4= github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.5/go.mod h1:hhbH6oRcou+LpXfA/0vPElh/e0M3aFeOblE1sssAAEk= github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE=
github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY=
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8=
github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0 h1:80pDB3Tpmb2RCSZORrK9/3iQxsd+w6vSzVqpT1FGiwE= github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0 h1:80pDB3Tpmb2RCSZORrK9/3iQxsd+w6vSzVqpT1FGiwE=
github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0/go.mod h1:6EZUGGNLPLh5Unt30uEoA+KQcByERfXIkax9qrc80nA= github.com/aws/aws-sdk-go-v2/service/route53 v1.62.0/go.mod h1:6EZUGGNLPLh5Unt30uEoA+KQcByERfXIkax9qrc80nA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.2 h1:U3ygWUhCpiSPYSHOrRhb3gOl9T5Y3kB8k5Vjs//57bE= github.com/aws/aws-sdk-go-v2/service/route53 v1.62.1 h1:1jIdwWOulae7bBLIgB36OZ0DINACb1wxM6wdGlx4eHE=
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.2/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8= github.com/aws/aws-sdk-go-v2/service/route53 v1.62.1/go.mod h1:tE2zGlMIlxWv+7Otap7ctRp3qeKqtnja7DZguj3Vu/Y=
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0 h1:SWTxh/EcUCDVqi/0s26V6pVUq0BBG7kx0tDTmF/hCgA= github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0=
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8= github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8=
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1 h1:C2dUPSnEpy4voWFIq3JNd8gN0Y5vYGDo44eUE58a/p8=
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ= github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU= github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 h1:eYnlt6QxnFINKzwxP5/Ucs1vkG7VT3Iezmvfgc2waUw= github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg= github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 h1:aM/Q24rIlS3bRAhTyFurowU8A0SMyGDtEOY/l/s/1Uw=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.8/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70= github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk= github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -81,16 +113,18 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=
github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE= github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/httprate v0.15.0 h1:j54xcWV9KGmPf/X4H32/aTH+wBlrvxL7P+SdnRqxh5g= github.com/go-chi/httprate v0.15.0 h1:j54xcWV9KGmPf/X4H32/aTH+wBlrvxL7P+SdnRqxh5g=
@@ -116,10 +150,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
github.com/go-playground/validator/v10 v10.29.0 h1:lQlF5VNJWNlRbRZNeOIkWElR+1LL/OuHcc0Kp14w1xk=
github.com/go-playground/validator/v10 v10.29.0/go.mod h1:D6QxqeMlgIPuT02L66f2ccrZ7AGgHkzKmmTMZhk/Kc4=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
@@ -133,6 +165,8 @@ github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
@@ -269,8 +303,12 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/sv-tools/openapi v0.2.1 h1:ES1tMQMJFGibWndMagvdoo34T1Vllxr1Nlm5wz6b1aA= github.com/sv-tools/openapi v0.2.1 h1:ES1tMQMJFGibWndMagvdoo34T1Vllxr1Nlm5wz6b1aA=
github.com/sv-tools/openapi v0.2.1/go.mod h1:k5VuZamTw1HuiS9p2Wl5YIDWzYnHG6/FgPOSFXLAhGg= github.com/sv-tools/openapi v0.2.1/go.mod h1:k5VuZamTw1HuiS9p2Wl5YIDWzYnHG6/FgPOSFXLAhGg=
github.com/sv-tools/openapi v0.4.0 h1:UhD9DVnGox1hfTePNclpUzUFgos57FvzT2jmcAuTOJ4=
github.com/sv-tools/openapi v0.4.0/go.mod h1:kD/dG+KP0+Fom1r6nvcj/ORtLus8d8enXT6dyRZDirE=
github.com/swaggo/swag/v2 v2.0.0-rc4 h1:SZ8cK68gcV6cslwrJMIOqPkJELRwq4gmjvk77MrvHvY= github.com/swaggo/swag/v2 v2.0.0-rc4 h1:SZ8cK68gcV6cslwrJMIOqPkJELRwq4gmjvk77MrvHvY=
github.com/swaggo/swag/v2 v2.0.0-rc4/go.mod h1:Ow7Y8gF16BTCDn8YxZbyKn8FkMLRUHekv1kROJZpbvE= github.com/swaggo/swag/v2 v2.0.0-rc4/go.mod h1:Ow7Y8gF16BTCDn8YxZbyKn8FkMLRUHekv1kROJZpbvE=
github.com/swaggo/swag/v2 v2.0.0-rc5 h1:fK7d6ET9rrEsdB8IyuwXREWMcyQN3N7gawGFbbrjgHk=
github.com/swaggo/swag/v2 v2.0.0-rc5/go.mod h1:kCL8Fu4Zl8d5tB2Bgj96b8wRowwrwk175bZHXfuGVFI=
github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948 h1:yL0l/u242MzDP6D0B5vGC+wxm5WRY+alQZy+dJk3bFI= github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948 h1:yL0l/u242MzDP6D0B5vGC+wxm5WRY+alQZy+dJk3bFI=
github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948/go.mod h1:a06d/M1pxWi51qiSrfGMHaEydtuXT06nha8N2aNQuXk= github.com/tuvistavie/securerandom v0.0.0-20140719024926-15512123a948/go.mod h1:a06d/M1pxWi51qiSrfGMHaEydtuXT06nha8N2aNQuXk=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
@@ -298,10 +336,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -310,6 +352,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -334,6 +378,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -349,12 +395,16 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=

View File

@@ -20,6 +20,7 @@ func mountDNSRoutes(r chi.Router, db *gorm.DB, authOrg func(http.Handler) http.H
d.Get("/domains/{domain_id}/records", handlers.ListRecordSets(db)) d.Get("/domains/{domain_id}/records", handlers.ListRecordSets(db))
d.Post("/domains/{domain_id}/records", handlers.CreateRecordSet(db)) d.Post("/domains/{domain_id}/records", handlers.CreateRecordSet(db))
d.Get("/records/{id}", handlers.GetRecordSet(db))
d.Patch("/records/{id}", handlers.UpdateRecordSet(db)) d.Patch("/records/{id}", handlers.UpdateRecordSet(db))
d.Delete("/records/{id}", handlers.DeleteRecordSet(db)) d.Delete("/records/{id}", handlers.DeleteRecordSet(db))
}) })

View File

@@ -37,7 +37,7 @@ func NewRouter(db *gorm.DB, jobs *bg.Jobs, studio http.Handler) http.Handler {
r.Use(middleware.Recoverer) r.Use(middleware.Recoverer)
r.Use(SecurityHeaders) r.Use(SecurityHeaders)
r.Use(requestBodyLimit(10 << 20)) r.Use(requestBodyLimit(10 << 20))
r.Use(httprate.LimitByIP(100, 1*time.Minute)) r.Use(httprate.LimitByIP(1000, 1*time.Minute))
r.Use(middleware.StripSlashes) r.Use(middleware.StripSlashes)
allowed := getAllowedOrigins() allowed := getAllowedOrigins()

View File

@@ -138,7 +138,11 @@ func NewJobs(gdb *gorm.DB, dbUrl string) (*Jobs, error) {
archer.WithTimeout(5*time.Minute), archer.WithTimeout(5*time.Minute),
) )
c.Register("cluster_action", ClusterActionWorker(gdb)) c.Register(
"cluster_action",
ClusterActionWorker(gdb),
archer.WithInstances(1),
)
return jobs, nil return jobs, nil
} }

View File

@@ -36,6 +36,21 @@ func ClusterActionWorker(db *gorm.DB) archer.WorkerFn {
var args ClusterActionArgs var args ClusterActionArgs
_ = j.ParseArguments(&args) _ = j.ParseArguments(&args)
runID, _ := uuid.Parse(j.ID)
updateRun := func(status string, errMsg string) {
updates := map[string]any{
"status": status,
"error": errMsg,
}
if status == "succeeded" || status == "failed" {
updates["finished_at"] = time.Now().UTC().Format(time.RFC3339)
}
db.Model(&models.ClusterRun{}).Where("id = ?", runID).Updates(updates)
}
updateRun("running", "")
logger := log.With(). logger := log.With().
Str("job", j.ID). Str("job", j.ID).
Str("cluster_id", args.ClusterID.String()). Str("cluster_id", args.ClusterID.String()).
@@ -56,18 +71,20 @@ func ClusterActionWorker(db *gorm.DB) archer.WorkerFn {
Preload("NodePools.Servers.SshKey"). Preload("NodePools.Servers.SshKey").
Where("id = ? AND organization_id = ?", args.ClusterID, args.OrgID). Where("id = ? AND organization_id = ?", args.ClusterID, args.OrgID).
First(&c).Error; err != nil { First(&c).Error; err != nil {
updateRun("failed", fmt.Errorf("load cluster: %w", err).Error())
return nil, fmt.Errorf("load cluster: %w", err) return nil, fmt.Errorf("load cluster: %w", err)
} }
// ---- Step 1: Prepare (mostly lifted from ClusterPrepareWorker) // ---- Step 1: Prepare (mostly lifted from ClusterPrepareWorker)
if err := setClusterStatus(db, c.ID, clusterStatusBootstrapping, ""); err != nil { if err := setClusterStatus(db, c.ID, clusterStatusBootstrapping, ""); err != nil {
updateRun("failed", err.Error())
return nil, fmt.Errorf("mark bootstrapping: %w", err) return nil, fmt.Errorf("mark bootstrapping: %w", err)
} }
c.Status = clusterStatusBootstrapping c.Status = clusterStatusBootstrapping
if err := validateClusterForPrepare(&c); err != nil { if err := validateClusterForPrepare(&c); err != nil {
_ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error())
updateRun("failed", err.Error())
return nil, fmt.Errorf("validate: %w", err) return nil, fmt.Errorf("validate: %w", err)
} }
@@ -75,6 +92,7 @@ func ClusterActionWorker(db *gorm.DB) archer.WorkerFn {
keyPayloads, sshConfig, err := buildSSHAssetsForCluster(db, &c, allServers) keyPayloads, sshConfig, err := buildSSHAssetsForCluster(db, &c, allServers)
if err != nil { if err != nil {
_ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error())
updateRun("failed", err.Error())
return nil, fmt.Errorf("build ssh assets: %w", err) return nil, fmt.Errorf("build ssh assets: %w", err)
} }
@@ -98,6 +116,7 @@ func ClusterActionWorker(db *gorm.DB) archer.WorkerFn {
orgKey, orgSecret, err := findOrCreateClusterAutomationKey(db, c.OrganizationID, c.ID, 24*time.Hour) orgKey, orgSecret, err := findOrCreateClusterAutomationKey(db, c.OrganizationID, c.ID, 24*time.Hour)
if err != nil { if err != nil {
_ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error())
updateRun("failed", err.Error())
return nil, fmt.Errorf("org key: %w", err) return nil, fmt.Errorf("org key: %w", err)
} }
dtoCluster.OrgKey = &orgKey dtoCluster.OrgKey = &orgKey
@@ -106,6 +125,7 @@ func ClusterActionWorker(db *gorm.DB) archer.WorkerFn {
payloadJSON, err := json.MarshalIndent(dtoCluster, "", " ") payloadJSON, err := json.MarshalIndent(dtoCluster, "", " ")
if err != nil { if err != nil {
_ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error())
updateRun("failed", err.Error())
return nil, fmt.Errorf("marshal payload: %w", err) return nil, fmt.Errorf("marshal payload: %w", err)
} }
@@ -115,11 +135,13 @@ func ClusterActionWorker(db *gorm.DB) archer.WorkerFn {
cancel() cancel()
if err != nil { if err != nil {
_ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error()) _ = setClusterStatus(db, c.ID, clusterStatusFailed, err.Error())
updateRun("failed", err.Error())
return nil, fmt.Errorf("push assets: %w", err) return nil, fmt.Errorf("push assets: %w", err)
} }
} }
if err := setClusterStatus(db, c.ID, clusterStatusPending, ""); err != nil { if err := setClusterStatus(db, c.ID, clusterStatusPending, ""); err != nil {
updateRun("failed", err.Error())
return nil, fmt.Errorf("mark pending: %w", err) return nil, fmt.Errorf("mark pending: %w", err)
} }
c.Status = clusterStatusPending c.Status = clusterStatusPending
@@ -132,11 +154,13 @@ func ClusterActionWorker(db *gorm.DB) archer.WorkerFn {
if err != nil { if err != nil {
logger.Error().Err(err).Str("output", out).Msg("ping-servers failed") logger.Error().Err(err).Str("output", out).Msg("ping-servers failed")
_ = setClusterStatus(db, c.ID, clusterStatusFailed, fmt.Sprintf("make ping-servers: %v", err)) _ = setClusterStatus(db, c.ID, clusterStatusFailed, fmt.Sprintf("make ping-servers: %v", err))
updateRun("failed", err.Error())
return nil, fmt.Errorf("ping-servers: %w", err) return nil, fmt.Errorf("ping-servers: %w", err)
} }
} }
if err := setClusterStatus(db, c.ID, clusterStatusProvisioning, ""); err != nil { if err := setClusterStatus(db, c.ID, clusterStatusProvisioning, ""); err != nil {
updateRun("failed", err.Error())
return nil, fmt.Errorf("mark provisioning: %w", err) return nil, fmt.Errorf("mark provisioning: %w", err)
} }
c.Status = clusterStatusProvisioning c.Status = clusterStatusProvisioning
@@ -149,13 +173,18 @@ func ClusterActionWorker(db *gorm.DB) archer.WorkerFn {
if err != nil { if err != nil {
logger.Error().Err(err).Str("output", out).Msg("bootstrap target failed") logger.Error().Err(err).Str("output", out).Msg("bootstrap target failed")
_ = setClusterStatus(db, c.ID, clusterStatusFailed, fmt.Sprintf("make %s: %v", args.MakeTarget, err)) _ = setClusterStatus(db, c.ID, clusterStatusFailed, fmt.Sprintf("make %s: %v", args.MakeTarget, err))
updateRun("failed", err.Error())
return nil, fmt.Errorf("make %s: %w", args.MakeTarget, err) return nil, fmt.Errorf("make %s: %w", args.MakeTarget, err)
} }
} }
if err := setClusterStatus(db, c.ID, clusterStatusReady, ""); err != nil { if err := setClusterStatus(db, c.ID, clusterStatusReady, ""); err != nil {
updateRun("failed", err.Error())
return nil, fmt.Errorf("mark ready: %w", err) return nil, fmt.Errorf("mark ready: %w", err)
} }
updateRun("succeeded", "")
return ClusterActionResult{ return ClusterActionResult{
Status: "ok", Status: "ok",
Action: args.Action, Action: args.Action,

View File

@@ -15,6 +15,7 @@ import (
"github.com/glueops/autoglue/internal/models" "github.com/glueops/autoglue/internal/models"
"github.com/glueops/autoglue/internal/utils" "github.com/glueops/autoglue/internal/utils"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"gorm.io/gorm" "gorm.io/gorm"
@@ -23,6 +24,8 @@ import (
"github.com/aws/aws-sdk-go-v2/credentials" "github.com/aws/aws-sdk-go-v2/credentials"
r53 "github.com/aws/aws-sdk-go-v2/service/route53" r53 "github.com/aws/aws-sdk-go-v2/service/route53"
r53types "github.com/aws/aws-sdk-go-v2/service/route53/types" r53types "github.com/aws/aws-sdk-go-v2/service/route53/types"
"github.com/aws/smithy-go"
smithyhttp "github.com/aws/smithy-go/transport/http"
) )
/************* args & small DTOs *************/ /************* args & small DTOs *************/
@@ -47,6 +50,9 @@ const externalDNSPoisonOwner = "autoglue-lock"
// ExternalDNS poison content fake owner so real external-dns skips it. // ExternalDNS poison content fake owner so real external-dns skips it.
const externalDNSPoisonValue = "heritage=external-dns,external-dns/owner=" + externalDNSPoisonOwner + ",external-dns/resource=manual/autoglue" const externalDNSPoisonValue = "heritage=external-dns,external-dns/owner=" + externalDNSPoisonOwner + ",external-dns/resource=manual/autoglue"
// Default TTL for non-alias records (alias not supported in this reconciler)
const defaultRecordTTLSeconds int64 = 300
/************* entrypoint worker *************/ /************* entrypoint worker *************/
func DNSReconsileWorker(db *gorm.DB, jobs *Jobs) archer.WorkerFn { func DNSReconsileWorker(db *gorm.DB, jobs *Jobs) archer.WorkerFn {
@@ -225,7 +231,14 @@ func processPendingRecordsForDomain(ctx context.Context, db *gorm.DB, d *models.
applied := 0 applied := 0
for i := range records { for i := range records {
if err := applyRecord(ctx, db, r53c, d, &records[i]); err != nil { if err := applyRecord(ctx, db, r53c, d, &records[i]); err != nil {
log.Error().Err(err).Str("rr", records[i].Name).Msg("[dns] apply record failed") log.Error().
Err(err).
Str("zone_id", d.ZoneID).
Str("domain", d.DomainName).
Str("record_id", records[i].ID.String()).
Str("name", records[i].Name).
Str("type", strings.ToUpper(records[i].Type)).
Msg("[dns] apply record failed")
_ = setRecordFailed(db, &records[i], err) _ = setRecordFailed(db, &records[i], err)
continue continue
} }
@@ -249,12 +262,24 @@ func applyRecord(ctx context.Context, db *gorm.DB, r53c *r53.Client, d *models.D
mname := markerName(fq) mname := markerName(fq)
expected := buildMarkerValue(d.OrganizationID.String(), r.ID.String(), r.Fingerprint) expected := buildMarkerValue(d.OrganizationID.String(), r.ID.String(), r.Fingerprint)
logCtx := log.With().
Str("zone_id", zoneID).
Str("domain", d.DomainName).
Str("fqdn", fq).
Str("rr_type", rt).
Str("record_id", r.ID.String()).
Str("org_id", d.OrganizationID.String()).
Logger()
start := time.Now()
// ---- ExternalDNS preflight ---- // ---- ExternalDNS preflight ----
extOwned, err := hasExternalDNSOwnership(ctx, r53c, zoneID, fq, rt) extOwned, err := hasExternalDNSOwnership(ctx, r53c, zoneID, fq, rt)
if err != nil { if err != nil {
return fmt.Errorf("external_dns_lookup: %w", err) return fmt.Errorf("external_dns_lookup: %w", err)
} }
if extOwned { if extOwned {
logCtx.Warn().Msg("[dns] ownership conflict: external-dns claims this record")
r.Owner = "external" r.Owner = "external"
_ = db.Save(r).Error _ = db.Save(r).Error
return fmt.Errorf("ownership_conflict: external-dns claims %s; refusing to modify", strings.TrimSuffix(fq, ".")) return fmt.Errorf("ownership_conflict: external-dns claims %s; refusing to modify", strings.TrimSuffix(fq, "."))
@@ -265,6 +290,7 @@ func applyRecord(ctx context.Context, db *gorm.DB, r53c *r53.Client, d *models.D
if err != nil { if err != nil {
return fmt.Errorf("marker lookup: %w", err) return fmt.Errorf("marker lookup: %w", err)
} }
hasForeignOwner := false hasForeignOwner := false
hasOurExact := false hasOurExact := false
for _, v := range markerVals { for _, v := range markerVals {
@@ -279,25 +305,26 @@ func applyRecord(ctx context.Context, db *gorm.DB, r53c *r53.Client, d *models.D
hasForeignOwner = true hasForeignOwner = true
} }
} }
logCtx.Debug().
Bool("externaldns_owned", extOwned).
Int("marker_txt_count", len(markerVals)).
Bool("marker_has_our_exact", hasOurExact).
Bool("marker_has_foreign", hasForeignOwner).
Msg("[dns] ownership preflight")
if hasForeignOwner { if hasForeignOwner {
logCtx.Warn().Msg("[dns] ownership conflict: foreign _autoglue marker")
r.Owner = "external" r.Owner = "external"
_ = db.Save(r).Error _ = db.Save(r).Error
return fmt.Errorf("ownership_conflict: marker for %s is owned by another controller; refusing to modify", strings.TrimSuffix(fq, ".")) return fmt.Errorf("ownership_conflict: marker for %s is owned by another controller; refusing to modify", strings.TrimSuffix(fq, "."))
} }
// Build RR change (UPSERT)
rrChange := r53types.Change{
Action: r53types.ChangeActionUpsert,
ResourceRecordSet: &r53types.ResourceRecordSet{
Name: aws.String(fq),
Type: r53types.RRType(rt),
},
}
// Decode user values // Decode user values
var userVals []string var userVals []string
if len(r.Values) > 0 { rawVals := strings.TrimSpace(string(r.Values))
if err := jsonUnmarshalStrict([]byte(r.Values), &userVals); err != nil { if rawVals != "" && rawVals != "null" {
if err := jsonUnmarshalStrict([]byte(rawVals), &userVals); err != nil {
return fmt.Errorf("values decode: %w", err) return fmt.Errorf("values decode: %w", err)
} }
} }
@@ -306,15 +333,38 @@ func applyRecord(ctx context.Context, db *gorm.DB, r53c *r53.Client, d *models.D
recs := make([]r53types.ResourceRecord, 0, len(userVals)) recs := make([]r53types.ResourceRecord, 0, len(userVals))
for _, v := range userVals { for _, v := range userVals {
v = strings.TrimSpace(v) v = strings.TrimSpace(v)
if v == "" {
continue
}
if rt == "TXT" && !(strings.HasPrefix(v, `"`) && strings.HasSuffix(v, `"`)) { if rt == "TXT" && !(strings.HasPrefix(v, `"`) && strings.HasSuffix(v, `"`)) {
v = strconv.Quote(v) v = strconv.Quote(v)
} }
recs = append(recs, r53types.ResourceRecord{Value: aws.String(v)}) recs = append(recs, r53types.ResourceRecord{Value: aws.String(v)})
} }
rrChange.ResourceRecordSet.ResourceRecords = recs
if r.TTL != nil { // Alias is NOT supported - enforce at least one value for all record types we manage
ttl := int64(*r.TTL) if len(recs) == 0 {
rrChange.ResourceRecordSet.TTL = aws.Int64(ttl) logCtx.Warn().
Str("raw_values", truncateForLog(string(r.Values), 240)).
Int("decoded_value_count", len(userVals)).
Msg("[dns] invalid record: no values (alias not supported)")
return fmt.Errorf("invalid_record: %s %s requires at least one value (alias not supported)", strings.TrimSuffix(fq, "."), rt)
}
ttl := defaultRecordTTLSeconds
if r.TTL != nil && *r.TTL > 0 {
ttl = int64(*r.TTL)
}
// Build RR change (UPSERT)
rrChange := r53types.Change{
Action: r53types.ChangeActionUpsert,
ResourceRecordSet: &r53types.ResourceRecordSet{
Name: aws.String(fq),
Type: r53types.RRType(rt),
TTL: aws.Int64(ttl),
ResourceRecords: recs,
},
} }
// Build marker TXT change (UPSERT) // Build marker TXT change (UPSERT)
@@ -323,7 +373,7 @@ func applyRecord(ctx context.Context, db *gorm.DB, r53c *r53.Client, d *models.D
ResourceRecordSet: &r53types.ResourceRecordSet{ ResourceRecordSet: &r53types.ResourceRecordSet{
Name: aws.String(mname), Name: aws.String(mname),
Type: r53types.RRTypeTxt, Type: r53types.RRTypeTxt,
TTL: aws.Int64(300), TTL: aws.Int64(defaultRecordTTLSeconds),
ResourceRecords: []r53types.ResourceRecord{ ResourceRecords: []r53types.ResourceRecord{
{Value: aws.String(strconv.Quote(expected))}, {Value: aws.String(strconv.Quote(expected))},
}, },
@@ -337,14 +387,26 @@ func applyRecord(ctx context.Context, db *gorm.DB, r53c *r53.Client, d *models.D
changes := []r53types.Change{rrChange, markerChange} changes := []r53types.Change{rrChange, markerChange}
changes = append(changes, poisonChanges...) changes = append(changes, poisonChanges...)
// Log what we are about to send
logCtx.Debug().
Interface("route53_change_batch", toLogChangeBatch(zoneID, changes)).
Msg("[dns] route53 request preview")
_, err = r53c.ChangeResourceRecordSets(ctx, &r53.ChangeResourceRecordSetsInput{ _, err = r53c.ChangeResourceRecordSets(ctx, &r53.ChangeResourceRecordSetsInput{
HostedZoneId: aws.String(zoneID), HostedZoneId: aws.String(zoneID),
ChangeBatch: &r53types.ChangeBatch{Changes: changes}, ChangeBatch: &r53types.ChangeBatch{Changes: changes},
}) })
if err != nil { if err != nil {
logAWSError(logCtx, err)
logCtx.Info().Dur("elapsed", time.Since(start)).Msg("[dns] apply failed")
return err return err
} }
logCtx.Info().
Dur("elapsed", time.Since(start)).
Int("change_count", len(changes)).
Msg("[dns] apply ok")
// Success → mark ready & ownership // Success → mark ready & ownership
r.Status = "ready" r.Status = "ready"
r.LastError = "" r.LastError = ""
@@ -352,6 +414,7 @@ func applyRecord(ctx context.Context, db *gorm.DB, r53c *r53.Client, d *models.D
if err := db.Save(r).Error; err != nil { if err := db.Save(r).Error; err != nil {
return err return err
} }
_ = hasOurExact // could be used to skip marker write in future _ = hasOurExact // could be used to skip marker write in future
return nil return nil
} }
@@ -568,7 +631,7 @@ func buildExternalDNSPoisonTXTChanges(fqdn, rrType string) []r53types.Change {
ResourceRecordSet: &r53types.ResourceRecordSet{ ResourceRecordSet: &r53types.ResourceRecordSet{
Name: aws.String(n), Name: aws.String(n),
Type: r53types.RRTypeTxt, Type: r53types.RRTypeTxt,
TTL: aws.Int64(300), TTL: aws.Int64(defaultRecordTTLSeconds),
ResourceRecords: []r53types.ResourceRecord{ ResourceRecords: []r53types.ResourceRecord{
{Value: aws.String(val)}, {Value: aws.String(val)},
}, },
@@ -595,3 +658,125 @@ func jsonUnmarshalStrict(b []byte, dst any) error {
} }
return json.Unmarshal(b, dst) return json.Unmarshal(b, dst)
} }
/************* logging DTOs & helpers *************/
type logRR struct {
Value string `json:"value"`
}
type logRRSet struct {
Action string `json:"action"`
Name string `json:"name"`
Type string `json:"type"`
TTL *int64 `json:"ttl,omitempty"`
Records []logRR `json:"records,omitempty"`
RecordCount int `json:"record_count"`
HasAliasTarget bool `json:"has_alias_target"`
SetIdentifier *string `json:"set_identifier,omitempty"`
}
type logChangeBatch struct {
HostedZoneID string `json:"hosted_zone_id"`
ChangeCount int `json:"change_count"`
Changes []logRRSet `json:"changes"`
}
func truncateForLog(s string, max int) string {
s = strings.TrimSpace(s)
if max <= 0 || len(s) <= max {
return s
}
return s[:max] + "…"
}
func toLogChangeBatch(zoneID string, changes []r53types.Change) logChangeBatch {
out := logChangeBatch{
HostedZoneID: zoneID,
ChangeCount: len(changes),
Changes: make([]logRRSet, 0, len(changes)),
}
for _, ch := range changes {
if ch.ResourceRecordSet == nil {
continue
}
rrs := ch.ResourceRecordSet
lc := logRRSet{
Action: string(ch.Action),
Name: aws.ToString(rrs.Name),
Type: string(rrs.Type),
TTL: rrs.TTL,
HasAliasTarget: rrs.AliasTarget != nil,
SetIdentifier: rrs.SetIdentifier,
RecordCount: len(rrs.ResourceRecords),
Records: make([]logRR, 0, min(len(rrs.ResourceRecords), 5)),
}
// Log up to first 5 values (truncate each) to avoid log bloat / secrets
for i, rr := range rrs.ResourceRecords {
if i >= 5 {
break
}
lc.Records = append(lc.Records, logRR{Value: truncateForLog(aws.ToString(rr.Value), 160)})
}
out.Changes = append(out.Changes, lc)
}
return out
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
// logAWSError extracts useful smithy/HTTP metadata (status code + request id + api code) into logs.
// logAWSError extracts useful smithy/HTTP metadata (status code + request id + api code) into logs.
func logAWSError(l zerolog.Logger, err error) {
// Add operation context if present
var opErr *smithy.OperationError
if errors.As(err, &opErr) {
l = l.With().
Str("aws_service", opErr.ServiceID).
Str("aws_operation", opErr.OperationName).
Logger()
err = opErr.Unwrap()
}
// HTTP status + request id (smithy-go transport/http)
var re *smithyhttp.ResponseError
if errors.As(err, &re) {
status := re.HTTPStatusCode()
reqID := ""
if resp := re.HTTPResponse(); resp != nil && resp.Header != nil {
reqID = resp.Header.Get("x-amzn-RequestId")
if reqID == "" {
reqID = resp.Header.Get("x-amz-request-id")
}
}
ev := l.Error().Int("http_status", status).Err(err)
if reqID != "" {
ev = ev.Str("aws_request_id", reqID)
}
ev.Msg("[dns] aws route53 call failed")
return
}
// API error code/message (best-effort)
var apiErr smithy.APIError
if errors.As(err, &apiErr) {
l.Error().
Str("aws_error_code", apiErr.ErrorCode()).
Str("aws_error_message", apiErr.ErrorMessage()).
Err(err).
Msg("[dns] aws route53 api error")
return
}
l.Error().Err(err).Msg("[dns] aws route53 error")
}

View File

@@ -211,13 +211,19 @@ func RunClusterAction(db *gorm.DB, jobs *bg.Jobs) http.HandlerFunc {
return return
} }
args := bg.ClusterActionArgs{
OrgID: orgID,
ClusterID: clusterID,
Action: action.MakeTarget,
MakeTarget: action.MakeTarget,
}
// Enqueue with run.ID as the job ID so the worker can look it up. // Enqueue with run.ID as the job ID so the worker can look it up.
_, enqueueErr := jobs.Enqueue( _, enqueueErr := jobs.Enqueue(
r.Context(), r.Context(),
run.ID.String(), run.ID.String(),
"cluster_action", "cluster_action",
bg.ClusterActionWorker, args,
archer.WithMaxRetries(3), archer.WithMaxRetries(0),
) )
if enqueueErr != nil { if enqueueErr != nil {
@@ -225,7 +231,7 @@ func RunClusterAction(db *gorm.DB, jobs *bg.Jobs) http.HandlerFunc {
Where("id = ?", run.ID). Where("id = ?", run.ID).
Updates(map[string]any{ Updates(map[string]any{
"status": models.ClusterRunStatusFailed, "status": models.ClusterRunStatusFailed,
"error": "failed to enqueue job", "error": "failed to enqueue job: " + enqueueErr.Error(),
"finished_at": time.Now().UTC(), "finished_at": time.Now().UTC(),
}).Error }).Error

View File

@@ -503,6 +503,50 @@ func ListRecordSets(db *gorm.DB) http.HandlerFunc {
} }
} }
// GetRecordSet godoc
//
// @ID GetRecordSet
// @Summary Get a record set (org scoped)
// @Tags DNS
// @Produce json
// @Param X-Org-ID header string false "Organization UUID"
// @Param id path string true "Record Set ID (UUID)"
// @Success 200 {object} dto.RecordSetResponse
// @Failure 403 {string} string "organization required"
// @Failure 404 {string} string "not found"
// @Router /dns/records/{id} [get]
func GetRecordSet(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
orgID, ok := httpmiddleware.OrgIDFrom(r.Context())
if !ok {
utils.WriteError(w, http.StatusForbidden, "org_required", "specify X-Org-ID")
return
}
id, err := uuid.Parse(chi.URLParam(r, "id"))
if err != nil {
utils.WriteError(w, http.StatusBadRequest, "bad_id", "invalid UUID")
return
}
var row models.RecordSet
if err := db.
Joins("Domain").
Where(`record_sets.id = ? AND "Domain"."organization_id" = ?`, id, orgID).
First(&row).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
utils.WriteError(w, http.StatusNotFound, "not_found", "record set not found")
return
}
utils.WriteError(w, http.StatusInternalServerError, "db_error", err.Error())
return
}
utils.WriteJSON(w, http.StatusOK, recordOut(&row))
}
}
// CreateRecordSet godoc // CreateRecordSet godoc
// //
// @ID CreateRecordSet // @ID CreateRecordSet

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

4186
internal/web/dist/assets/index-GteqH5KT.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,9 +5,9 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AutoGlue</title> <title>AutoGlue</title>
<script type="module" crossorigin src="/assets/index-CyGsiYei.js"></script> <script type="module" crossorigin src="/assets/index-GteqH5KT.js"></script>
<link rel="modulepreload" crossorigin href="/assets/react-Dt2M6tWj.js"> <link rel="modulepreload" crossorigin href="/assets/react-v1TLhXpT.js">
<link rel="stylesheet" crossorigin href="/assets/index-VHZG0dIU.css"> <link rel="stylesheet" crossorigin href="/assets/index-Cdjh6IZW.css">
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

Binary file not shown.

Binary file not shown.

View File

@@ -1,2 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,4 +1,4 @@
FROM postgres:17.7@sha256:44640f16641cf36716cabd011e2f7eb4742b6b6b19f4488ddcbb7c250e5c9753 FROM postgres:17.7@sha256:dca7512acaa113409df7e40d977d801e53c0c8088e45d4311a45b4065ccfdcd3
RUN cd /var/lib/postgresql/ && \ RUN cd /var/lib/postgresql/ && \
openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req -keyout privkey.pem && \ openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req -keyout privkey.pem && \

View File

@@ -16,6 +16,6 @@
"prepare": "npm run build" "prepare": "npm run build"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^4.0 || ^5.0" "typescript": "5.9.3"
} }
} }

View File

@@ -46,41 +46,41 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.561.0", "lucide-react": "^0.563.0",
"motion": "^12.23.26", "motion": "^12.23.26",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"rapidoc": "^9.3.8", "rapidoc": "^9.3.8",
"react": "^19.2.3", "react": "^19.2.3",
"react-day-picker": "^9.12.0", "react-day-picker": "^9.13.0",
"react-dom": "^19.2.3", "react-dom": "^19.2.3",
"react-hook-form": "^7.68.0", "react-hook-form": "^7.70.0",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-resizable-panels": "^3.0.6", "react-resizable-panels": "^3.0.6",
"react-router-dom": "^7.10.1", "react-router-dom": "^7.11.0",
"recharts": "2.15.4", "recharts": "2.15.4",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18", "tailwindcss": "^4.1.18",
"vaul": "^1.1.2", "vaul": "^1.1.2",
"zod": "^4.1.13" "zod": "^4.2.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.39.2", "@eslint/js": "9.39.2",
"@ianvs/prettier-plugin-sort-imports": "4.7.0", "@ianvs/prettier-plugin-sort-imports": "4.7.0",
"@types/node": "25.0.1", "@types/node": "25.2.2",
"@types/react": "19.2.7", "@types/react": "19.2.13",
"@types/react-dom": "19.2.3", "@types/react-dom": "19.2.3",
"@vitejs/plugin-react": "5.1.2", "@vitejs/plugin-react": "5.1.3",
"eslint": "9.39.2", "eslint": "9.39.2",
"eslint-plugin-react-hooks": "7.0.1", "eslint-plugin-react-hooks": "7.0.1",
"eslint-plugin-react-refresh": "0.4.24", "eslint-plugin-react-refresh": "0.5.0",
"globals": "16.5.0", "globals": "16.5.0",
"prettier": "3.7.4", "prettier": "3.8.1",
"prettier-plugin-tailwindcss": "0.7.2", "prettier-plugin-tailwindcss": "0.7.2",
"shadcn": "3.6.0", "shadcn": "3.8.3",
"tw-animate-css": "1.4.0", "tw-animate-css": "1.4.0",
"typescript": "5.9.3", "typescript": "5.9.3",
"typescript-eslint": "8.50.0", "typescript-eslint": "8.54.0",
"vite": "7.2.7" "vite": "7.3.1"
} }
} }

View File

@@ -946,13 +946,12 @@ export const ClustersPage = () => {
{/* Configure dialog (attachments + kubeconfig + node pools + actions/runs) */} {/* Configure dialog (attachments + kubeconfig + node pools + actions/runs) */}
<Dialog open={!!configCluster} onOpenChange={(open) => !open && setConfigCluster(null)}> <Dialog open={!!configCluster} onOpenChange={(open) => !open && setConfigCluster(null)}>
<DialogContent className="max-h-[90vh] w-full max-w-3xl overflow-y-auto"> <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-2xl lg:max-w-250 ">
<DialogHeader> <DialogHeader>
<DialogTitle> <DialogTitle>
Configure Cluster{configCluster?.name ? `: ${configCluster.name}` : ""} Configure Cluster{configCluster?.name ? `: ${configCluster.name}` : ""}
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
{configCluster && ( {configCluster && (
<div className="space-y-6 py-2"> <div className="space-y-6 py-2">
{/* Cluster Actions */} {/* Cluster Actions */}

View File

@@ -68,6 +68,10 @@ const AWS_ALLOWED_SERVICES = ["route53", "s3", "ec2", "iam", "rds", "dynamodb"]
type AwsSvc = (typeof AWS_ALLOWED_SERVICES)[number] type AwsSvc = (typeof AWS_ALLOWED_SERVICES)[number]
// -------------------- Schemas -------------------- // -------------------- Schemas --------------------
// Zod v4 gotchas you hit:
// - .partial() cannot be used if the object contains refinements/effects (often true once you have transforms/refines).
// - .extend() cannot overwrite keys after refinements (requires .safeExtend()).
// Easiest fix: define CREATE and UPDATE schemas separately (no .partial(), no post-refinement .extend()).
const createCredentialSchema = z const createCredentialSchema = z
.object({ .object({
@@ -91,6 +95,16 @@ const createCredentialSchema = z
secret: z.any(), secret: z.any(),
}) })
.superRefine((val, ctx) => { .superRefine((val, ctx) => {
// scope required unless provider scope
if (val.scope_kind !== "provider" && !val.scope) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["scope"],
message: `scope is required`,
})
}
// AWS scope checks
if (val.credential_provider === "aws") { if (val.credential_provider === "aws") {
if (val.scope_kind === "service") { if (val.scope_kind === "service") {
const svc = (val.scope as any)?.service const svc = (val.scope as any)?.service
@@ -112,23 +126,25 @@ const createCredentialSchema = z
}) })
} }
} }
if (val.kind === "aws_access_key") { }
const sk = val.secret ?? {}
const id = sk.access_key_id // secret requiredness by kind (create always validates)
if (typeof id !== "string" || !/^[A-Z0-9]{20}$/.test(id)) { if (val.kind === "aws_access_key") {
ctx.addIssue({ const sk = val.secret ?? {}
code: z.ZodIssueCode.custom, const id = sk.access_key_id
path: ["secret"], if (typeof id !== "string" || !/^[A-Z0-9]{20}$/.test(id)) {
message: `access_key_id must be 20 chars (A-Z0-9)`, ctx.addIssue({
}) code: z.ZodIssueCode.custom,
} path: ["secret"],
if (typeof sk.secret_access_key !== "string" || sk.secret_access_key.length < 10) { message: `access_key_id must be 20 chars (A-Z0-9)`,
ctx.addIssue({ })
code: z.ZodIssueCode.custom, }
path: ["secret"], if (typeof sk.secret_access_key !== "string" || sk.secret_access_key.length < 10) {
message: `secret_access_key is required`, ctx.addIssue({
}) code: z.ZodIssueCode.custom,
} path: ["secret"],
message: `secret_access_key is required`,
})
} }
} }
@@ -142,6 +158,7 @@ const createCredentialSchema = z
}) })
} }
} }
if (val.kind === "basic_auth") { if (val.kind === "basic_auth") {
const s = val.secret ?? {} const s = val.secret ?? {}
if (!s.username || !s.password) { if (!s.username || !s.password) {
@@ -152,6 +169,7 @@ const createCredentialSchema = z
}) })
} }
} }
if (val.kind === "oauth2") { if (val.kind === "oauth2") {
const s = val.secret ?? {} const s = val.secret ?? {}
if (!s.client_id || !s.client_secret || !s.refresh_token) { if (!s.client_id || !s.client_secret || !s.refresh_token) {
@@ -162,30 +180,144 @@ const createCredentialSchema = z
}) })
} }
} }
if (val.scope_kind !== "provider" && !val.scope) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["scope"],
message: `scope is required`,
})
}
}) })
type CreateCredentialValues = z.input<typeof createCredentialSchema> type CreateCredentialValues = z.input<typeof createCredentialSchema>
const updateCredentialSchema = createCredentialSchema.partial().extend({
name: z.string().min(1, "Name is required").max(100).optional(), // UPDATE schema: all fields optional, and validations are "patch-friendly".
}) const updateCredentialSchema = z
.object({
credential_provider: z
.enum(["aws", "cloudflare", "hetzner", "digitalocean", "generic"])
.optional(),
kind: z.enum(["aws_access_key", "api_token", "basic_auth", "oauth2"]).optional(),
schema_version: z.number().optional(),
name: z.string().min(1, "Name is required").max(100).optional(),
scope_kind: z.enum(["provider", "service", "resource"]).optional(),
scope_version: z.number().optional(),
scope: z.any().optional(),
// allow "" so your form can keep empty strings; buildUpdateBody will drop them
account_id: z.string().optional().or(z.literal("")),
region: z.string().optional().or(z.literal("")),
secret: z.any().optional(),
})
.superRefine((val, ctx) => {
// If scope_kind is being changed to non-provider, require scope in the patch
if (typeof val.scope_kind !== "undefined") {
if (val.scope_kind !== "provider" && !val.scope) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["scope"],
message: `scope is required`,
})
}
}
// AWS scope checks only if we have enough info
if (val.credential_provider === "aws") {
if (val.scope_kind === "service" && typeof val.scope !== "undefined") {
const svc = (val.scope as any)?.service
if (!AWS_ALLOWED_SERVICES.includes(svc)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["scope"],
message: `For AWS service scope, "service" must be one of: ${AWS_ALLOWED_SERVICES.join(", ")}`,
})
}
}
if (val.scope_kind === "resource" && typeof val.scope !== "undefined") {
const arn = (val.scope as any)?.arn
if (typeof arn !== "string" || !arn.startsWith("arn:")) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["scope"],
message: `For AWS resource scope, "arn" must start with "arn:"`,
})
}
}
}
// Secret validation on update:
// - only validate if rotating secret OR changing kind
// - if rotating secret but kind is NOT provided, skip kind-specific checks (backend can validate)
const rotatingSecret = typeof val.secret !== "undefined"
const changingKind = typeof val.kind !== "undefined"
if (!rotatingSecret && !changingKind) return
if (!val.kind) return
if (val.kind === "aws_access_key") {
const sk = val.secret ?? {}
const id = sk.access_key_id
if (typeof id !== "string" || !/^[A-Z0-9]{20}$/.test(id)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["secret"],
message: `access_key_id must be 20 chars (A-Z0-9)`,
})
}
if (typeof sk.secret_access_key !== "string" || sk.secret_access_key.length < 10) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["secret"],
message: `secret_access_key is required`,
})
}
}
if (val.kind === "api_token") {
const token = (val.secret ?? {}).token
if (!token) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["secret"],
message: `token is required`,
})
}
}
if (val.kind === "basic_auth") {
const s = val.secret ?? {}
if (!s.username || !s.password) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["secret"],
message: `username and password are required`,
})
}
}
if (val.kind === "oauth2") {
const s = val.secret ?? {}
if (!s.client_id || !s.client_secret || !s.refresh_token) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["secret"],
message: `client_id, client_secret, and refresh_token are required`,
})
}
}
})
type UpdateCredentialValues = z.input<typeof updateCredentialSchema>
// -------------------- Helpers -------------------- // -------------------- Helpers --------------------
function pretty(obj: unknown) { function pretty(obj: unknown) {
try { try {
return JSON.stringify(JSON.parse(obj as string), null, 2) if (obj == null) return ""
if (typeof obj === "string") {
try {
return JSON.stringify(JSON.parse(obj), null, 2)
} catch {
return obj
}
}
return JSON.stringify(obj, null, 2)
} catch { } catch {
return "" return ""
} }
} }
function extractErr(e: any): string { function extractErr(e: any): string {
const raw = (e as any)?.body ?? (e as any)?.response ?? (e as any)?.message const raw = (e as any)?.body ?? (e as any)?.response ?? (e as any)?.message
if (typeof raw === "string") return raw if (typeof raw === "string") return raw
@@ -252,9 +384,9 @@ function buildCreateBody(v: CreateCredentialValues) {
} }
// Build exact PATCH body (only provided fields) // Build exact PATCH body (only provided fields)
function buildUpdateBody(v: z.infer<typeof updateCredentialSchema>) { function buildUpdateBody(v: UpdateCredentialValues) {
const body: any = {} const body: any = {}
const keys: (keyof typeof v)[] = [ const keys: (keyof UpdateCredentialValues)[] = [
"name", "name",
"account_id", "account_id",
"region", "region",
@@ -316,7 +448,7 @@ export const CredentialPage = () => {
// Update // Update
const updateMutation = useMutation({ const updateMutation = useMutation({
mutationFn: (payload: { id: string; body: z.infer<typeof updateCredentialSchema> }) => mutationFn: (payload: { id: string; body: UpdateCredentialValues }) =>
credentialsApi.updateCredential(payload.id, buildUpdateBody(payload.body)), credentialsApi.updateCredential(payload.id, buildUpdateBody(payload.body)),
onSuccess: async () => { onSuccess: async () => {
await qc.invalidateQueries({ queryKey: ["credentials"] }) await qc.invalidateQueries({ queryKey: ["credentials"] })
@@ -362,7 +494,7 @@ export const CredentialPage = () => {
mode: "onBlur", mode: "onBlur",
}) })
const editForm = useForm<z.input<typeof updateCredentialSchema>>({ const editForm = useForm<UpdateCredentialValues>({
resolver: zodResolver(updateCredentialSchema), resolver: zodResolver(updateCredentialSchema),
defaultValues: {}, defaultValues: {},
mode: "onBlur", mode: "onBlur",
@@ -371,7 +503,8 @@ export const CredentialPage = () => {
function openEdit(row: any) { function openEdit(row: any) {
setEditingId(row.id) setEditingId(row.id)
editForm.reset({ editForm.reset({
provider: row.provider, // FIX: correct key (was "provider" in your original)
credential_provider: row.credential_provider,
kind: row.kind, kind: row.kind,
schema_version: row.schema_version ?? 1, schema_version: row.schema_version ?? 1,
name: row.name, name: row.name,
@@ -380,7 +513,7 @@ export const CredentialPage = () => {
account_id: row.account_id ?? "", account_id: row.account_id ?? "",
region: row.region ?? "", region: row.region ?? "",
scope: row.scope ?? (row.scope_kind === "provider" ? {} : undefined), scope: row.scope ?? (row.scope_kind === "provider" ? {} : undefined),
secret: undefined, secret: undefined, // keep existing unless user rotates
} as any) } as any)
setUseRawEditSecretJSON(false) setUseRawEditSecretJSON(false)
setEditOpen(true) setEditOpen(true)
@@ -394,7 +527,7 @@ export const CredentialPage = () => {
return items.filter((c: any) => return items.filter((c: any) =>
[ [
c.name, c.name,
c.provider, c.credential_provider,
c.kind, c.kind,
c.scope_kind, c.scope_kind,
c.account_id, c.account_id,
@@ -436,6 +569,7 @@ export const CredentialPage = () => {
function ensureCreateDefaultsForSecret() { function ensureCreateDefaultsForSecret() {
if (useRawSecretJSON) return if (useRawSecretJSON) return
if (credential_provider === "aws" && kind === "aws_access_key") { if (credential_provider === "aws" && kind === "aws_access_key") {
const s = createForm.getValues("secret") ?? {} const s = createForm.getValues("secret") ?? {}
setCreateSecret({ setCreateSecret({
@@ -459,7 +593,7 @@ export const CredentialPage = () => {
} }
function onChangeCreateScopeKind(next: "provider" | "service" | "resource") { function onChangeCreateScopeKind(next: "provider" | "service" | "resource") {
createForm.setValue("scope_kind", next) createForm.setValue("scope_kind", next, { shouldDirty: true, shouldValidate: true })
if (next === "provider") setCreateScope({}) if (next === "provider") setCreateScope({})
if (next === "service") setCreateScope({ service: "route53" as AwsSvc }) if (next === "service") setCreateScope({ service: "route53" as AwsSvc })
if (next === "resource") setCreateScope({ arn: "" }) if (next === "resource") setCreateScope({ arn: "" })
@@ -905,6 +1039,7 @@ export const CredentialPage = () => {
client_secret: e.target.value, client_secret: e.target.value,
}) })
} }
placeholder="••••••••••"
/> />
)} )}
/> />
@@ -933,7 +1068,6 @@ export const CredentialPage = () => {
)} )}
<DialogFooter className="gap-2"> <DialogFooter className="gap-2">
{/* Preview Create button */}
<Button <Button
type="button" type="button"
variant="secondary" variant="secondary"
@@ -1260,9 +1394,7 @@ export const CredentialPage = () => {
<FormItem> <FormItem>
<FormLabel>Rotate Secret (JSON)</FormLabel> <FormLabel>Rotate Secret (JSON)</FormLabel>
<Textarea <Textarea
value={ value={typeof field.value === "string" ? field.value : pretty(field.value)}
typeof field.value === "string" ? field.value : pretty(field.value ?? {})
}
onChange={(e) => { onChange={(e) => {
try { try {
field.onChange(JSON.parse(e.target.value)) field.onChange(JSON.parse(e.target.value))
@@ -1281,7 +1413,6 @@ export const CredentialPage = () => {
)} )}
<DialogFooter className="gap-2"> <DialogFooter className="gap-2">
{/* Preview Update button */}
<Button <Button
type="button" type="button"
variant="secondary" variant="secondary"

View File

@@ -128,6 +128,10 @@ const credLabel = (c: DtoCredentialOut) => {
} }
// ---------- zod schemas ---------- // ---------- zod schemas ----------
// IMPORTANT (Zod v4):
// - `.partial()` cannot be used on object schemas containing refinements/effects.
// Your schemas contain effects via `.transform(...)` and refinements via `.superRefine(...)` / `.refine(...)`,
// so we define UPDATE schemas explicitly instead of using `.partial()`.
const createDomainSchema = z.object({ const createDomainSchema = z.object({
domain_name: z domain_name: z
@@ -144,8 +148,22 @@ const createDomainSchema = z.object({
}) })
type CreateDomainValues = z.input<typeof createDomainSchema> type CreateDomainValues = z.input<typeof createDomainSchema>
const updateDomainSchema = createDomainSchema.partial() // Update: all optional; replicate the normalization safely
type UpdateDomainValues = z.infer<typeof updateDomainSchema> const updateDomainSchema = z.object({
domain_name: z
.string()
.min(1, "Domain is required")
.max(253)
.transform((s) => s.trim().replace(/\.$/, "").toLowerCase())
.optional(),
credential_id: z.string().uuid("Pick a credential").optional(),
zone_id: z
.string()
.optional()
.or(z.literal(""))
.transform((v) => (v ? v.trim() : undefined)),
})
type UpdateDomainValues = z.input<typeof updateDomainSchema>
const ttlSchema = z const ttlSchema = z
.union([ .union([
@@ -182,7 +200,42 @@ const createRecordSchema = z
}) })
type CreateRecordValues = z.input<typeof createRecordSchema> type CreateRecordValues = z.input<typeof createRecordSchema>
const updateRecordSchema = createRecordSchema.partial() // Update: all optional. Only enforce "values required"/"CNAME exactly one" if valuesCsv is present.
// Only validate ttl if present (ttlSchema already optional).
const updateRecordSchema = z
.object({
name: z
.string()
.min(1, "Name required")
.max(253)
.transform((s) => s.trim().replace(/\.$/, "").toLowerCase())
.optional(),
type: z.enum(rrtypes as [string, ...string[]]).optional(),
ttl: ttlSchema,
valuesCsv: z.string().optional(),
})
.superRefine((vals, ctx) => {
const hasValues = typeof vals.valuesCsv !== "undefined"
if (!hasValues) return
const arr = parseCommaList(vals.valuesCsv ?? "")
if (arr.length === 0) {
ctx.addIssue({
code: "custom",
path: ["valuesCsv"],
message: "At least one value is required",
})
}
// We can only enforce CNAME rule if `type` is provided in patch (or you can enforce always if you want).
if (vals.type === "CNAME" && arr.length !== 1) {
ctx.addIssue({
code: "custom",
path: ["valuesCsv"],
message: "CNAME requires exactly one value",
})
}
})
type UpdateRecordValues = z.input<typeof updateRecordSchema> type UpdateRecordValues = z.input<typeof updateRecordSchema>
// ---------- main ---------- // ---------- main ----------
@@ -224,12 +277,9 @@ export const DnsPage = () => {
const r53Credentials = useMemo(() => (credentialQ.data ?? []).filter(isR53), [credentialQ.data]) const r53Credentials = useMemo(() => (credentialQ.data ?? []).filter(isR53), [credentialQ.data])
useEffect(() => { useEffect(() => {
const setSelectedDns = () => { if (!selected && domainsQ.data && domainsQ.data.length) {
if (!selected && domainsQ.data && domainsQ.data.length) { setSelected(domainsQ.data[0]!)
setSelected(domainsQ.data[0]!)
}
} }
setSelectedDns()
}, [domainsQ.data, selected]) }, [domainsQ.data, selected])
const filteredDomains = useMemo(() => { const filteredDomains = useMemo(() => {
@@ -237,7 +287,7 @@ export const DnsPage = () => {
if (!filter.trim()) return list if (!filter.trim()) return list
const f = filter.toLowerCase() const f = filter.toLowerCase()
return list.filter((d) => return list.filter((d) =>
[d.domain_name, d.zone_id, d.status, d.domain_name] [d.domain_name, d.zone_id, d.status]
.filter(Boolean) .filter(Boolean)
.map((x) => String(x).toLowerCase()) .map((x) => String(x).toLowerCase())
.some((s) => s.includes(f)) .some((s) => s.includes(f))
@@ -271,6 +321,7 @@ export const DnsPage = () => {
const editDomainForm = useForm<UpdateDomainValues>({ const editDomainForm = useForm<UpdateDomainValues>({
resolver: zodResolver(updateDomainSchema), resolver: zodResolver(updateDomainSchema),
defaultValues: {},
}) })
const openEditDomain = (d: DtoDomainResponse) => { const openEditDomain = (d: DtoDomainResponse) => {
@@ -283,10 +334,20 @@ export const DnsPage = () => {
setEditDomOpen(true) setEditDomOpen(true)
} }
// Build PATCH body (dont send empty strings)
const buildUpdateDomainBody = (vals: UpdateDomainValues): DtoUpdateDomainRequest => {
const body: any = {}
if (typeof vals.domain_name !== "undefined") body.domain_name = vals.domain_name
if (typeof vals.credential_id !== "undefined" && vals.credential_id !== "")
body.credential_id = vals.credential_id
if (typeof vals.zone_id !== "undefined" && vals.zone_id !== "") body.zone_id = vals.zone_id
return body as DtoUpdateDomainRequest
}
const updateDomainMut = useMutation({ const updateDomainMut = useMutation({
mutationFn: (vals: UpdateDomainValues) => { mutationFn: (vals: UpdateDomainValues) => {
if (!selected) throw new Error("No domain selected") if (!selected) throw new Error("No domain selected")
return dnsApi.updateDomain(selected.id!, vals as unknown as DtoUpdateDomainRequest) return dnsApi.updateDomain(selected.id!, buildUpdateDomainBody(vals))
}, },
onSuccess: async () => { onSuccess: async () => {
toast.success("Domain updated") toast.success("Domain updated")
@@ -338,7 +399,6 @@ export const DnsPage = () => {
const body: DtoCreateRecordSetRequest = { const body: DtoCreateRecordSetRequest = {
name: vals.name, name: vals.name,
type: vals.type, type: vals.type,
// omit ttl when empty/undefined
...(vals.ttl ? { ttl: vals.ttl as unknown as number } : {}), ...(vals.ttl ? { ttl: vals.ttl as unknown as number } : {}),
values: parseCommaList(vals.valuesCsv ?? ""), values: parseCommaList(vals.valuesCsv ?? ""),
} }
@@ -356,6 +416,7 @@ export const DnsPage = () => {
const editRecForm = useForm<UpdateRecordValues>({ const editRecForm = useForm<UpdateRecordValues>({
resolver: zodResolver(updateRecordSchema), resolver: zodResolver(updateRecordSchema),
defaultValues: {},
}) })
const openEditRecord = (r: DtoRecordSetResponse) => { const openEditRecord = (r: DtoRecordSetResponse) => {
@@ -374,15 +435,12 @@ export const DnsPage = () => {
mutationFn: async (vals: UpdateRecordValues) => { mutationFn: async (vals: UpdateRecordValues) => {
if (!editingRecord) throw new Error("No record selected") if (!editingRecord) throw new Error("No record selected")
const body: DtoUpdateRecordSetRequest = {} const body: DtoUpdateRecordSetRequest = {}
if (vals.name !== undefined) body.name = vals.name
if (vals.type !== undefined) body.type = vals.type if (typeof vals.name !== "undefined") body.name = vals.name
if (vals.ttl !== undefined && vals.ttl !== null) { if (typeof vals.type !== "undefined") body.type = vals.type
// if blank string came through it would have been filtered; when undefined, omit if (typeof vals.ttl !== "undefined") body.ttl = vals.ttl as unknown as number | undefined
body.ttl = vals.ttl as unknown as number | undefined if (typeof vals.valuesCsv !== "undefined") body.values = parseCommaList(vals.valuesCsv)
}
if (vals.valuesCsv !== undefined) {
body.values = parseCommaList(vals.valuesCsv)
}
return dnsApi.updateRecordSetsByDomain(editingRecord.id!, body) return dnsApi.updateRecordSetsByDomain(editingRecord.id!, body)
}, },
onSuccess: async () => { onSuccess: async () => {
@@ -556,7 +614,14 @@ export const DnsPage = () => {
</td> </td>
<td className="px-3 py-2"> <td className="px-3 py-2">
<div className="flex items-center justify-end gap-2"> <div className="flex items-center justify-end gap-2">
<Button size="icon" variant="ghost" onClick={() => openEditDomain(d)}> <Button
size="icon"
variant="ghost"
onClick={(e) => {
e.stopPropagation()
openEditDomain(d)
}}
>
<Pencil className="h-4 w-4" /> <Pencil className="h-4 w-4" />
</Button> </Button>
<AlertDialog> <AlertDialog>
@@ -650,10 +715,7 @@ export const DnsPage = () => {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Type</FormLabel> <FormLabel>Type</FormLabel>
<Select <Select onValueChange={field.onChange} value={field.value as string}>
onValueChange={field.onChange}
defaultValue={field.value as string}
>
<FormControl> <FormControl>
<SelectTrigger> <SelectTrigger>
<SelectValue /> <SelectValue />
@@ -969,7 +1031,7 @@ export const DnsPage = () => {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Type</FormLabel> <FormLabel>Type</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value as string}> <Select onValueChange={field.onChange} value={field.value as string}>
<FormControl> <FormControl>
<SelectTrigger> <SelectTrigger>
<SelectValue /> <SelectValue />

View File

@@ -305,6 +305,7 @@ export const MePage = () => {
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>Id</TableHead>
<TableHead>Name</TableHead> <TableHead>Name</TableHead>
<TableHead>Domain</TableHead> <TableHead>Domain</TableHead>
</TableRow> </TableRow>
@@ -312,6 +313,7 @@ export const MePage = () => {
<TableBody> <TableBody>
{meQ.data?.organizations?.map((o) => ( {meQ.data?.organizations?.map((o) => (
<TableRow key={o.id}> <TableRow key={o.id}>
<TableCell>{o.id}</TableCell>
<TableCell>{o.name}</TableCell> <TableCell>{o.name}</TableCell>
<TableCell>{(o as any).domain ?? "—"}</TableCell> <TableCell>{(o as any).domain ?? "—"}</TableCell>
</TableRow> </TableRow>

View File

@@ -53,13 +53,17 @@ type Role = (typeof ROLE_OPTIONS)[number]
const STATUS = ["pending", "provisioning", "ready", "failed"] as const const STATUS = ["pending", "provisioning", "ready", "failed"] as const
type Status = (typeof STATUS)[number] type Status = (typeof STATUS)[number]
// ---------- Zod schemas ----------
// Zod v4: `.partial()` cannot be used on schemas with refinements/effects.
// createServerSchema has a refinement, so define updateServerSchema explicitly.
const createServerSchema = z const createServerSchema = z
.object({ .object({
hostname: z.string().trim().max(60, "Max 60 chars"), hostname: z.string().trim().max(60, "Max 60 chars"),
public_ip_address: z.string().trim().optional().or(z.literal("")), public_ip_address: z.string().trim().optional().or(z.literal("")),
private_ip_address: z.string().trim().min(1, "Private IP address required"), private_ip_address: z.string().trim().min(1, "Private IP address required"),
role: z.enum(ROLE_OPTIONS), role: z.enum(ROLE_OPTIONS),
ssh_key_id: z.uuid("Pick a valid SSH key"), ssh_key_id: z.string().uuid("Pick a valid SSH key"),
ssh_user: z.string().trim().min(1, "SSH user is required"), ssh_user: z.string().trim().min(1, "SSH user is required"),
status: z.enum(STATUS).default("pending"), status: z.enum(STATUS).default("pending"),
}) })
@@ -69,8 +73,33 @@ const createServerSchema = z
) )
type CreateServerInput = z.input<typeof createServerSchema> type CreateServerInput = z.input<typeof createServerSchema>
const updateServerSchema = createServerSchema.partial() // Patch-friendly update schema:
type UpdateServerValues = z.infer<typeof updateServerSchema> // - all fields optional
// - only enforce "public ip required" if role is being set to bastion in the patch
const updateServerSchema = z
.object({
hostname: z.string().trim().max(60, "Max 60 chars").optional(),
public_ip_address: z.string().trim().optional().or(z.literal("")),
private_ip_address: z.string().trim().min(1, "Private IP address required").optional(),
role: z.enum(ROLE_OPTIONS).optional(),
ssh_key_id: z.string().uuid("Pick a valid SSH key").optional(),
ssh_user: z.string().trim().min(1, "SSH user is required").optional(),
status: z.enum(STATUS).optional(),
})
.superRefine((v, ctx) => {
// If updating role to bastion, require public_ip_address in the patch
if (v.role === "bastion") {
const pub = typeof v.public_ip_address === "string" ? v.public_ip_address.trim() : ""
if (!pub) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["public_ip_address"],
message: "Public IP required for bastion",
})
}
}
})
type UpdateServerValues = z.input<typeof updateServerSchema>
function StatusBadge({ status }: { status: Status }) { function StatusBadge({ status }: { status: Status }) {
const v = const v =
@@ -88,6 +117,27 @@ function StatusBadge({ status }: { status: Status }) {
) )
} }
// Build PATCH body: omit undefined and empty strings (so optional inputs can be cleared in UI without sending "")
function buildUpdateBody(values: UpdateServerValues) {
const body: any = {}
const keys: (keyof UpdateServerValues)[] = [
"hostname",
"public_ip_address",
"private_ip_address",
"role",
"ssh_key_id",
"ssh_user",
"status",
]
for (const k of keys) {
const v = values[k]
if (typeof v === "undefined") continue
if (v === "") continue
body[k] = v
}
return body
}
export const ServerPage = () => { export const ServerPage = () => {
const [filter, setFilter] = useState<string>("") const [filter, setFilter] = useState<string>("")
const [createOpen, setCreateOpen] = useState<boolean>(false) const [createOpen, setCreateOpen] = useState<boolean>(false)
@@ -180,13 +230,12 @@ export const ServerPage = () => {
}) })
const roleIsBastionU = watchedRoleUpdate === "bastion" const roleIsBastionU = watchedRoleUpdate === "bastion"
const pubUpdate = watchedPublicIpAddressUpdate?.trim() ?? "" const pubUpdate = watchedPublicIpAddressUpdate?.trim() ?? ""
const needPubUpdate = roleIsBastionU && pubUpdate === "" const needPubUpdate = roleIsBastionU && pubUpdate === ""
const updateMut = useMutation({ const updateMut = useMutation({
mutationFn: ({ id, values }: { id: string; values: UpdateServerValues }) => mutationFn: ({ id, values }: { id: string; values: UpdateServerValues }) =>
serversApi.updateServer(id, values as any), serversApi.updateServer(id, buildUpdateBody(values) as any),
onSuccess: async () => { onSuccess: async () => {
await qc.invalidateQueries({ queryKey: ["servers"] }) await qc.invalidateQueries({ queryKey: ["servers"] })
setUpdateOpen(false) setUpdateOpen(false)
@@ -279,7 +328,7 @@ export const ServerPage = () => {
</div> </div>
<Select <Select
value={roleFilter || "all"} // map "" -> "all" for the UI value={roleFilter || "all"}
onValueChange={(v) => setRoleFilter(v === "all" ? "" : (v as Role))} onValueChange={(v) => setRoleFilter(v === "all" ? "" : (v as Role))}
> >
<SelectTrigger className="w-36"> <SelectTrigger className="w-36">
@@ -296,14 +345,14 @@ export const ServerPage = () => {
</Select> </Select>
<Select <Select
value={statusFilter || "all"} // map "" -> "all" for the UI value={statusFilter || "all"}
onValueChange={(v) => setStatusFilter(v === "all" ? "" : (v as Status))} onValueChange={(v) => setStatusFilter(v === "all" ? "" : (v as Status))}
> >
<SelectTrigger className="w-40"> <SelectTrigger className="w-40">
<SelectValue placeholder="Status (all)" /> <SelectValue placeholder="Status (all)" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="all">All statuses</SelectItem> {/* sentinel */} <SelectItem value="all">All statuses</SelectItem>
{STATUS.map((s) => ( {STATUS.map((s) => (
<SelectItem key={s} value={s}> <SelectItem key={s} value={s}>
{s} {s}

File diff suppressed because it is too large Load Diff