@serve.zone/gitops 2.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/.smartconfig.json +114 -0
  2. package/binary/gitops.ts +4 -0
  3. package/changelog.md +185 -0
  4. package/cli.child.js +4 -0
  5. package/cli.js +4 -0
  6. package/cli.ts.js +5 -0
  7. package/deno.json +10 -0
  8. package/dist_serve/bundle.js +36362 -0
  9. package/dist_serve/index.html +33 -0
  10. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  11. package/dist_ts/00_commitinfo_data.js +9 -0
  12. package/dist_ts/cache/classes.cache.cleaner.d.ts +23 -0
  13. package/dist_ts/cache/classes.cache.cleaner.js +61 -0
  14. package/dist_ts/cache/classes.cached.document.d.ts +30 -0
  15. package/dist_ts/cache/classes.cached.document.js +101 -0
  16. package/dist_ts/cache/classes.cachedb.d.ts +22 -0
  17. package/dist_ts/cache/classes.cachedb.js +58 -0
  18. package/dist_ts/cache/classes.secrets.scan.service.d.ts +51 -0
  19. package/dist_ts/cache/classes.secrets.scan.service.js +237 -0
  20. package/dist_ts/cache/documents/classes.cached.project.d.ts +13 -0
  21. package/dist_ts/cache/documents/classes.cached.project.js +101 -0
  22. package/dist_ts/cache/documents/classes.cached.secret.d.ts +24 -0
  23. package/dist_ts/cache/documents/classes.cached.secret.js +158 -0
  24. package/dist_ts/cache/documents/index.d.ts +2 -0
  25. package/dist_ts/cache/documents/index.js +3 -0
  26. package/dist_ts/cache/index.d.ts +7 -0
  27. package/dist_ts/cache/index.js +6 -0
  28. package/dist_ts/classes/actionlog.d.ts +19 -0
  29. package/dist_ts/classes/actionlog.js +44 -0
  30. package/dist_ts/classes/connectionmanager.d.ts +57 -0
  31. package/dist_ts/classes/connectionmanager.js +247 -0
  32. package/dist_ts/classes/gitopsapp.d.ts +30 -0
  33. package/dist_ts/classes/gitopsapp.js +101 -0
  34. package/dist_ts/classes/jobmanager.d.ts +47 -0
  35. package/dist_ts/classes/jobmanager.js +301 -0
  36. package/dist_ts/classes/jobrunners/autobookstackdocs.runner.d.ts +29 -0
  37. package/dist_ts/classes/jobrunners/autobookstackdocs.runner.js +361 -0
  38. package/dist_ts/classes/jobrunners/base.jobrunner.d.ts +14 -0
  39. package/dist_ts/classes/jobrunners/base.jobrunner.js +3 -0
  40. package/dist_ts/classes/jobrunners/index.d.ts +5 -0
  41. package/dist_ts/classes/jobrunners/index.js +14 -0
  42. package/dist_ts/classes/managedsecrets.manager.d.ts +47 -0
  43. package/dist_ts/classes/managedsecrets.manager.js +247 -0
  44. package/dist_ts/classes/syncmanager.d.ts +189 -0
  45. package/dist_ts/classes/syncmanager.js +1787 -0
  46. package/dist_ts/index.d.ts +6 -0
  47. package/dist_ts/index.js +32 -0
  48. package/dist_ts/logging.d.ts +49 -0
  49. package/dist_ts/logging.js +134 -0
  50. package/dist_ts/opsserver/classes.opsserver.d.ts +25 -0
  51. package/dist_ts/opsserver/classes.opsserver.js +70 -0
  52. package/dist_ts/opsserver/handlers/actionlog.handler.d.ts +9 -0
  53. package/dist_ts/opsserver/handlers/actionlog.handler.js +24 -0
  54. package/dist_ts/opsserver/handlers/actions.handler.d.ts +9 -0
  55. package/dist_ts/opsserver/handlers/actions.handler.js +38 -0
  56. package/dist_ts/opsserver/handlers/admin.handler.d.ts +19 -0
  57. package/dist_ts/opsserver/handlers/admin.handler.js +96 -0
  58. package/dist_ts/opsserver/handlers/connections.handler.d.ts +10 -0
  59. package/dist_ts/opsserver/handlers/connections.handler.js +109 -0
  60. package/dist_ts/opsserver/handlers/groups.handler.d.ts +9 -0
  61. package/dist_ts/opsserver/handlers/groups.handler.js +24 -0
  62. package/dist_ts/opsserver/handlers/index.d.ts +13 -0
  63. package/dist_ts/opsserver/handlers/index.js +14 -0
  64. package/dist_ts/opsserver/handlers/jobs.handler.d.ts +16 -0
  65. package/dist_ts/opsserver/handlers/jobs.handler.js +146 -0
  66. package/dist_ts/opsserver/handlers/logs.handler.d.ts +9 -0
  67. package/dist_ts/opsserver/handlers/logs.handler.js +21 -0
  68. package/dist_ts/opsserver/handlers/managedsecrets.handler.d.ts +11 -0
  69. package/dist_ts/opsserver/handlers/managedsecrets.handler.js +110 -0
  70. package/dist_ts/opsserver/handlers/pipelines.handler.d.ts +31 -0
  71. package/dist_ts/opsserver/handlers/pipelines.handler.js +204 -0
  72. package/dist_ts/opsserver/handlers/projects.handler.d.ts +9 -0
  73. package/dist_ts/opsserver/handlers/projects.handler.js +24 -0
  74. package/dist_ts/opsserver/handlers/secrets.handler.d.ts +10 -0
  75. package/dist_ts/opsserver/handlers/secrets.handler.js +171 -0
  76. package/dist_ts/opsserver/handlers/sync.handler.d.ts +16 -0
  77. package/dist_ts/opsserver/handlers/sync.handler.js +166 -0
  78. package/dist_ts/opsserver/handlers/webhook.handler.d.ts +7 -0
  79. package/dist_ts/opsserver/handlers/webhook.handler.js +55 -0
  80. package/dist_ts/opsserver/helpers/guards.d.ts +5 -0
  81. package/dist_ts/opsserver/helpers/guards.js +12 -0
  82. package/dist_ts/opsserver/index.d.ts +1 -0
  83. package/dist_ts/opsserver/index.js +2 -0
  84. package/dist_ts/paths.d.ts +9 -0
  85. package/dist_ts/paths.js +13 -0
  86. package/dist_ts/plugins.d.ts +25 -0
  87. package/dist_ts/plugins.js +32 -0
  88. package/dist_ts/providers/classes.baseprovider.d.ts +51 -0
  89. package/dist_ts/providers/classes.baseprovider.js +17 -0
  90. package/dist_ts/providers/classes.giteaprovider.d.ts +40 -0
  91. package/dist_ts/providers/classes.giteaprovider.js +224 -0
  92. package/dist_ts/providers/classes.gitlabprovider.d.ts +39 -0
  93. package/dist_ts/providers/classes.gitlabprovider.js +207 -0
  94. package/dist_ts/providers/index.d.ts +3 -0
  95. package/dist_ts/providers/index.js +4 -0
  96. package/dist_ts/storage/classes.storagemanager.d.ts +33 -0
  97. package/dist_ts/storage/classes.storagemanager.js +135 -0
  98. package/dist_ts/storage/index.d.ts +2 -0
  99. package/dist_ts/storage/index.js +2 -0
  100. package/dist_ts/timers.d.ts +4 -0
  101. package/dist_ts/timers.js +24 -0
  102. package/dist_ts_bundled/bundle.d.ts +4 -0
  103. package/dist_ts_bundled/bundle.js +12 -0
  104. package/dist_ts_interfaces/data/actionlog.d.ts +12 -0
  105. package/dist_ts_interfaces/data/actionlog.js +2 -0
  106. package/dist_ts_interfaces/data/branch.d.ts +8 -0
  107. package/dist_ts_interfaces/data/branch.js +2 -0
  108. package/dist_ts_interfaces/data/connection.d.ts +12 -0
  109. package/dist_ts_interfaces/data/connection.js +2 -0
  110. package/dist_ts_interfaces/data/group.d.ts +10 -0
  111. package/dist_ts_interfaces/data/group.js +2 -0
  112. package/dist_ts_interfaces/data/identity.d.ts +7 -0
  113. package/dist_ts_interfaces/data/identity.js +2 -0
  114. package/dist_ts_interfaces/data/index.d.ts +11 -0
  115. package/dist_ts_interfaces/data/index.js +12 -0
  116. package/dist_ts_interfaces/data/job.d.ts +37 -0
  117. package/dist_ts_interfaces/data/job.js +2 -0
  118. package/dist_ts_interfaces/data/managedsecret.d.ts +37 -0
  119. package/dist_ts_interfaces/data/managedsecret.js +2 -0
  120. package/dist_ts_interfaces/data/pipeline.d.ts +22 -0
  121. package/dist_ts_interfaces/data/pipeline.js +2 -0
  122. package/dist_ts_interfaces/data/project.d.ts +12 -0
  123. package/dist_ts_interfaces/data/project.js +2 -0
  124. package/dist_ts_interfaces/data/secret.d.ts +11 -0
  125. package/dist_ts_interfaces/data/secret.js +2 -0
  126. package/dist_ts_interfaces/data/sync.d.ts +34 -0
  127. package/dist_ts_interfaces/data/sync.js +2 -0
  128. package/dist_ts_interfaces/index.d.ts +5 -0
  129. package/dist_ts_interfaces/index.js +8 -0
  130. package/dist_ts_interfaces/plugins.d.ts +2 -0
  131. package/dist_ts_interfaces/plugins.js +4 -0
  132. package/dist_ts_interfaces/requests/actionlog.d.ts +15 -0
  133. package/dist_ts_interfaces/requests/actionlog.js +3 -0
  134. package/dist_ts_interfaces/requests/actions.d.ts +31 -0
  135. package/dist_ts_interfaces/requests/actions.js +3 -0
  136. package/dist_ts_interfaces/requests/admin.d.ts +31 -0
  137. package/dist_ts_interfaces/requests/admin.js +3 -0
  138. package/dist_ts_interfaces/requests/connections.d.ts +71 -0
  139. package/dist_ts_interfaces/requests/connections.js +3 -0
  140. package/dist_ts_interfaces/requests/groups.d.ts +14 -0
  141. package/dist_ts_interfaces/requests/groups.js +3 -0
  142. package/dist_ts_interfaces/requests/index.d.ts +13 -0
  143. package/dist_ts_interfaces/requests/index.js +14 -0
  144. package/dist_ts_interfaces/requests/jobs.d.ts +86 -0
  145. package/dist_ts_interfaces/requests/jobs.js +3 -0
  146. package/dist_ts_interfaces/requests/logs.d.ts +14 -0
  147. package/dist_ts_interfaces/requests/logs.js +3 -0
  148. package/dist_ts_interfaces/requests/managedsecrets.d.ts +84 -0
  149. package/dist_ts_interfaces/requests/managedsecrets.js +3 -0
  150. package/dist_ts_interfaces/requests/pipelines.d.ts +55 -0
  151. package/dist_ts_interfaces/requests/pipelines.js +3 -0
  152. package/dist_ts_interfaces/requests/projects.d.ts +14 -0
  153. package/dist_ts_interfaces/requests/projects.js +3 -0
  154. package/dist_ts_interfaces/requests/secrets.d.ts +72 -0
  155. package/dist_ts_interfaces/requests/secrets.js +3 -0
  156. package/dist_ts_interfaces/requests/sync.d.ts +120 -0
  157. package/dist_ts_interfaces/requests/sync.js +3 -0
  158. package/dist_ts_interfaces/requests/webhook.d.ts +13 -0
  159. package/dist_ts_interfaces/requests/webhook.js +3 -0
  160. package/license +21 -0
  161. package/package.json +81 -0
  162. package/readme.md +177 -0
  163. package/readme.todo.md +3 -0
  164. package/ts/00_commitinfo_data.ts +8 -0
  165. package/ts/cache/classes.cache.cleaner.ts +69 -0
  166. package/ts/cache/classes.cached.document.ts +57 -0
  167. package/ts/cache/classes.cachedb.ts +72 -0
  168. package/ts/cache/classes.secrets.scan.service.ts +267 -0
  169. package/ts/cache/documents/classes.cached.project.ts +32 -0
  170. package/ts/cache/documents/classes.cached.secret.ts +81 -0
  171. package/ts/cache/documents/index.ts +2 -0
  172. package/ts/cache/index.ts +7 -0
  173. package/ts/classes/actionlog.ts +57 -0
  174. package/ts/classes/connectionmanager.ts +263 -0
  175. package/ts/classes/gitopsapp.ts +128 -0
  176. package/ts/classes/jobmanager.ts +337 -0
  177. package/ts/classes/jobrunners/autobookstackdocs.runner.ts +435 -0
  178. package/ts/classes/jobrunners/base.jobrunner.ts +16 -0
  179. package/ts/classes/jobrunners/index.ts +17 -0
  180. package/ts/classes/managedsecrets.manager.ts +322 -0
  181. package/ts/classes/syncmanager.ts +2117 -0
  182. package/ts/index.ts +37 -0
  183. package/ts/logging.ts +162 -0
  184. package/ts/opsserver/classes.opsserver.ts +86 -0
  185. package/ts/opsserver/handlers/actionlog.handler.ts +30 -0
  186. package/ts/opsserver/handlers/actions.handler.ts +50 -0
  187. package/ts/opsserver/handlers/admin.handler.ts +122 -0
  188. package/ts/opsserver/handlers/connections.handler.ts +162 -0
  189. package/ts/opsserver/handlers/groups.handler.ts +32 -0
  190. package/ts/opsserver/handlers/index.ts +13 -0
  191. package/ts/opsserver/handlers/jobs.handler.ts +189 -0
  192. package/ts/opsserver/handlers/logs.handler.ts +29 -0
  193. package/ts/opsserver/handlers/managedsecrets.handler.ts +158 -0
  194. package/ts/opsserver/handlers/pipelines.handler.ts +281 -0
  195. package/ts/opsserver/handlers/projects.handler.ts +32 -0
  196. package/ts/opsserver/handlers/secrets.handler.ts +224 -0
  197. package/ts/opsserver/handlers/sync.handler.ts +224 -0
  198. package/ts/opsserver/handlers/webhook.handler.ts +62 -0
  199. package/ts/opsserver/helpers/guards.ts +16 -0
  200. package/ts/opsserver/index.ts +1 -0
  201. package/ts/paths.ts +19 -0
  202. package/ts/plugins.ts +38 -0
  203. package/ts/providers/classes.baseprovider.ts +99 -0
  204. package/ts/providers/classes.giteaprovider.ts +279 -0
  205. package/ts/providers/classes.gitlabprovider.ts +265 -0
  206. package/ts/providers/index.ts +3 -0
  207. package/ts/storage/classes.storagemanager.ts +144 -0
  208. package/ts/storage/index.ts +2 -0
  209. package/ts/timers.ts +34 -0
  210. package/ts_interfaces/data/actionlog.ts +13 -0
  211. package/ts_interfaces/data/branch.ts +9 -0
  212. package/ts_interfaces/data/connection.ts +13 -0
  213. package/ts_interfaces/data/group.ts +10 -0
  214. package/ts_interfaces/data/identity.ts +7 -0
  215. package/ts_interfaces/data/index.ts +11 -0
  216. package/ts_interfaces/data/job.ts +42 -0
  217. package/ts_interfaces/data/managedsecret.ts +41 -0
  218. package/ts_interfaces/data/pipeline.ts +32 -0
  219. package/ts_interfaces/data/project.ts +12 -0
  220. package/ts_interfaces/data/secret.ts +11 -0
  221. package/ts_interfaces/data/sync.ts +37 -0
  222. package/ts_interfaces/index.ts +9 -0
  223. package/ts_interfaces/plugins.ts +6 -0
  224. package/ts_interfaces/requests/actionlog.ts +19 -0
  225. package/ts_interfaces/requests/actions.ts +39 -0
  226. package/ts_interfaces/requests/admin.ts +43 -0
  227. package/ts_interfaces/requests/connections.ts +95 -0
  228. package/ts_interfaces/requests/groups.ts +18 -0
  229. package/ts_interfaces/requests/index.ts +13 -0
  230. package/ts_interfaces/requests/jobs.ts +118 -0
  231. package/ts_interfaces/requests/logs.ts +18 -0
  232. package/ts_interfaces/requests/managedsecrets.ts +112 -0
  233. package/ts_interfaces/requests/pipelines.ts +71 -0
  234. package/ts_interfaces/requests/projects.ts +18 -0
  235. package/ts_interfaces/requests/secrets.ts +92 -0
  236. package/ts_interfaces/requests/sync.ts +157 -0
  237. package/ts_interfaces/requests/webhook.ts +18 -0
  238. package/ts_web/00_commitinfo_data.ts +8 -0
  239. package/ts_web/appstate.ts +1251 -0
  240. package/ts_web/elements/gitops-dashboard.ts +350 -0
  241. package/ts_web/elements/index.ts +10 -0
  242. package/ts_web/elements/shared/css.ts +29 -0
  243. package/ts_web/elements/shared/index.ts +1 -0
  244. package/ts_web/elements/views/actionlog/index.ts +101 -0
  245. package/ts_web/elements/views/actions/index.ts +209 -0
  246. package/ts_web/elements/views/buildlog/index.ts +196 -0
  247. package/ts_web/elements/views/connections/index.ts +260 -0
  248. package/ts_web/elements/views/groups/index.ts +134 -0
  249. package/ts_web/elements/views/jobs/index.ts +424 -0
  250. package/ts_web/elements/views/managedsecrets/index.ts +502 -0
  251. package/ts_web/elements/views/overview/index.ts +86 -0
  252. package/ts_web/elements/views/pipelines/index.ts +561 -0
  253. package/ts_web/elements/views/projects/index.ts +149 -0
  254. package/ts_web/elements/views/secrets/index.ts +310 -0
  255. package/ts_web/elements/views/sync/index.ts +512 -0
  256. package/ts_web/index.ts +7 -0
  257. package/ts_web/plugins.ts +15 -0
  258. package/tsconfig.json +15 -0
@@ -0,0 +1,247 @@
1
+ import * as plugins from '../plugins.js';
2
+ import { logger } from '../logging.js';
3
+ const MANAGED_SECRETS_PREFIX = '/managed-secrets/';
4
+ const KEYCHAIN_PREFIX = 'keychain:';
5
+ const KEYCHAIN_ID_PREFIX = 'gitops-msecret-';
6
+ const SECRET_KEY_PREFIX = 'GITOPS_';
7
+ export class ManagedSecretsManager {
8
+ storageManager;
9
+ smartSecret;
10
+ connectionManager;
11
+ secrets = [];
12
+ constructor(storageManager, smartSecret, connectionManager) {
13
+ this.storageManager = storageManager;
14
+ this.smartSecret = smartSecret;
15
+ this.connectionManager = connectionManager;
16
+ }
17
+ async init() {
18
+ await this.loadSecrets();
19
+ }
20
+ // ---- Storage helpers ----
21
+ keychainId(secretId) {
22
+ return `${KEYCHAIN_ID_PREFIX}${secretId}`;
23
+ }
24
+ prefixedKey(key) {
25
+ return `${SECRET_KEY_PREFIX}${key}`;
26
+ }
27
+ async loadSecrets() {
28
+ const keys = await this.storageManager.list(MANAGED_SECRETS_PREFIX);
29
+ this.secrets = [];
30
+ for (const key of keys) {
31
+ const stored = await this.storageManager.getJSON(key);
32
+ if (stored) {
33
+ this.secrets.push(stored);
34
+ }
35
+ }
36
+ if (this.secrets.length > 0) {
37
+ logger.info(`Loaded ${this.secrets.length} managed secret(s)`);
38
+ }
39
+ }
40
+ async persistSecret(stored, realValue) {
41
+ // Store real value in keychain
42
+ await this.smartSecret.setSecret(this.keychainId(stored.id), realValue);
43
+ // Save JSON with sentinel
44
+ const jsonStored = { ...stored, value: `${KEYCHAIN_PREFIX}${this.keychainId(stored.id)}` };
45
+ await this.storageManager.setJSON(`${MANAGED_SECRETS_PREFIX}${stored.id}.json`, jsonStored);
46
+ // Update in-memory sentinel too
47
+ stored.value = jsonStored.value;
48
+ }
49
+ async removeFromStorage(id) {
50
+ await this.smartSecret.deleteSecret(this.keychainId(id));
51
+ await this.storageManager.delete(`${MANAGED_SECRETS_PREFIX}${id}.json`);
52
+ }
53
+ async getSecretValue(id) {
54
+ return await this.smartSecret.getSecret(this.keychainId(id));
55
+ }
56
+ toApiModel(stored) {
57
+ return {
58
+ id: stored.id,
59
+ key: stored.key,
60
+ description: stored.description,
61
+ targets: stored.targets,
62
+ targetStatuses: stored.targetStatuses,
63
+ createdAt: stored.createdAt,
64
+ updatedAt: stored.updatedAt,
65
+ lastPushedAt: stored.lastPushedAt,
66
+ };
67
+ }
68
+ // ---- Push logic ----
69
+ async pushToTargets(stored, mode, targetsOverride) {
70
+ const targets = targetsOverride || stored.targets;
71
+ const value = mode === 'upsert' ? await this.getSecretValue(stored.id) : null;
72
+ const prefixedKey = this.prefixedKey(stored.key);
73
+ const results = [];
74
+ for (const target of targets) {
75
+ const status = {
76
+ connectionId: target.connectionId,
77
+ scope: target.scope,
78
+ scopeId: target.scopeId,
79
+ scopeName: target.scopeName,
80
+ status: 'pending',
81
+ };
82
+ try {
83
+ const provider = this.connectionManager.getProvider(target.connectionId);
84
+ if (mode === 'upsert') {
85
+ // Try update first; if it fails, create
86
+ try {
87
+ if (target.scope === 'project') {
88
+ await provider.updateProjectSecret(target.scopeId, prefixedKey, value);
89
+ }
90
+ else {
91
+ await provider.updateGroupSecret(target.scopeId, prefixedKey, value);
92
+ }
93
+ }
94
+ catch {
95
+ // Secret doesn't exist yet — create it
96
+ if (target.scope === 'project') {
97
+ await provider.createProjectSecret(target.scopeId, prefixedKey, value);
98
+ }
99
+ else {
100
+ await provider.createGroupSecret(target.scopeId, prefixedKey, value);
101
+ }
102
+ }
103
+ }
104
+ else {
105
+ // mode === 'delete'
106
+ try {
107
+ if (target.scope === 'project') {
108
+ await provider.deleteProjectSecret(target.scopeId, prefixedKey);
109
+ }
110
+ else {
111
+ await provider.deleteGroupSecret(target.scopeId, prefixedKey);
112
+ }
113
+ }
114
+ catch {
115
+ // Secret may not exist on target — that's fine
116
+ }
117
+ }
118
+ status.status = 'success';
119
+ status.lastPushedAt = Date.now();
120
+ }
121
+ catch (err) {
122
+ status.status = 'error';
123
+ status.error = err instanceof Error ? err.message : String(err);
124
+ }
125
+ results.push(status);
126
+ }
127
+ return results;
128
+ }
129
+ // ---- Public API ----
130
+ async getAll() {
131
+ return this.secrets.map((s) => this.toApiModel(s));
132
+ }
133
+ async getById(id) {
134
+ const stored = this.secrets.find((s) => s.id === id);
135
+ return stored ? this.toApiModel(stored) : null;
136
+ }
137
+ async create(key, value, description, targets) {
138
+ // Validate key
139
+ if (key.toUpperCase().startsWith(SECRET_KEY_PREFIX)) {
140
+ throw new Error(`Key must not start with ${SECRET_KEY_PREFIX} — the prefix is added automatically`);
141
+ }
142
+ if (this.secrets.some((s) => s.key === key)) {
143
+ throw new Error(`A managed secret with key "${key}" already exists`);
144
+ }
145
+ const now = Date.now();
146
+ const stored = {
147
+ id: crypto.randomUUID(),
148
+ key,
149
+ description,
150
+ value: '', // will be set by persistSecret
151
+ targets,
152
+ targetStatuses: [],
153
+ createdAt: now,
154
+ updatedAt: now,
155
+ };
156
+ this.secrets.push(stored);
157
+ await this.persistSecret(stored, value);
158
+ // Push to all targets
159
+ const pushResults = await this.pushToTargets(stored, 'upsert');
160
+ stored.targetStatuses = pushResults;
161
+ stored.lastPushedAt = now;
162
+ stored.updatedAt = now;
163
+ await this.storageManager.setJSON(`${MANAGED_SECRETS_PREFIX}${stored.id}.json`, {
164
+ ...stored,
165
+ value: `${KEYCHAIN_PREFIX}${this.keychainId(stored.id)}`,
166
+ });
167
+ logger.info(`Created managed secret "${key}" with ${targets.length} target(s)`);
168
+ return { managedSecret: this.toApiModel(stored), pushResults };
169
+ }
170
+ async update(id, updates) {
171
+ const stored = this.secrets.find((s) => s.id === id);
172
+ if (!stored)
173
+ throw new Error(`Managed secret not found: ${id}`);
174
+ const now = Date.now();
175
+ // Update value in keychain if provided
176
+ if (updates.value !== undefined) {
177
+ await this.smartSecret.setSecret(this.keychainId(id), updates.value);
178
+ }
179
+ if (updates.description !== undefined) {
180
+ stored.description = updates.description;
181
+ }
182
+ // Handle target changes — delete from removed targets
183
+ let removedTargets = [];
184
+ if (updates.targets !== undefined) {
185
+ const oldTargets = stored.targets;
186
+ const newTargetKeys = new Set(updates.targets.map((t) => `${t.connectionId}:${t.scope}:${t.scopeId}`));
187
+ removedTargets = oldTargets.filter((t) => !newTargetKeys.has(`${t.connectionId}:${t.scope}:${t.scopeId}`));
188
+ stored.targets = updates.targets;
189
+ }
190
+ stored.updatedAt = now;
191
+ // Delete from removed targets
192
+ if (removedTargets.length > 0) {
193
+ await this.pushToTargets(stored, 'delete', removedTargets);
194
+ }
195
+ // Push to current targets
196
+ const pushResults = await this.pushToTargets(stored, 'upsert');
197
+ stored.targetStatuses = pushResults;
198
+ stored.lastPushedAt = now;
199
+ await this.storageManager.setJSON(`${MANAGED_SECRETS_PREFIX}${stored.id}.json`, {
200
+ ...stored,
201
+ value: `${KEYCHAIN_PREFIX}${this.keychainId(stored.id)}`,
202
+ });
203
+ logger.info(`Updated managed secret "${stored.key}"`);
204
+ return { managedSecret: this.toApiModel(stored), pushResults };
205
+ }
206
+ async delete(id) {
207
+ const stored = this.secrets.find((s) => s.id === id);
208
+ if (!stored)
209
+ throw new Error(`Managed secret not found: ${id}`);
210
+ // Best-effort: remove from all targets
211
+ const deleteResults = await this.pushToTargets(stored, 'delete');
212
+ // Remove from local storage regardless
213
+ const idx = this.secrets.indexOf(stored);
214
+ this.secrets.splice(idx, 1);
215
+ await this.removeFromStorage(id);
216
+ logger.info(`Deleted managed secret "${stored.key}"`);
217
+ return { ok: true, deleteResults };
218
+ }
219
+ async pushOne(id) {
220
+ const stored = this.secrets.find((s) => s.id === id);
221
+ if (!stored)
222
+ throw new Error(`Managed secret not found: ${id}`);
223
+ const now = Date.now();
224
+ const pushResults = await this.pushToTargets(stored, 'upsert');
225
+ stored.targetStatuses = pushResults;
226
+ stored.lastPushedAt = now;
227
+ stored.updatedAt = now;
228
+ await this.storageManager.setJSON(`${MANAGED_SECRETS_PREFIX}${stored.id}.json`, {
229
+ ...stored,
230
+ value: `${KEYCHAIN_PREFIX}${this.keychainId(stored.id)}`,
231
+ });
232
+ return { managedSecret: this.toApiModel(stored), pushResults };
233
+ }
234
+ async pushAll() {
235
+ const results = [];
236
+ for (const stored of this.secrets) {
237
+ const { pushResults } = await this.pushOne(stored.id);
238
+ results.push({
239
+ managedSecretId: stored.id,
240
+ key: stored.key,
241
+ pushResults,
242
+ });
243
+ }
244
+ return results;
245
+ }
246
+ }
247
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFuYWdlZHNlY3JldHMubWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NsYXNzZXMvbWFuYWdlZHNlY3JldHMubWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBS3ZDLE1BQU0sc0JBQXNCLEdBQUcsbUJBQW1CLENBQUM7QUFDbkQsTUFBTSxlQUFlLEdBQUcsV0FBVyxDQUFDO0FBQ3BDLE1BQU0sa0JBQWtCLEdBQUcsaUJBQWlCLENBQUM7QUFDN0MsTUFBTSxpQkFBaUIsR0FBRyxTQUFTLENBQUM7QUFFcEMsTUFBTSxPQUFPLHFCQUFxQjtJQUl0QjtJQUNBO0lBQ0E7SUFMRixPQUFPLEdBQTJDLEVBQUUsQ0FBQztJQUU3RCxZQUNVLGNBQThCLEVBQzlCLFdBQTRDLEVBQzVDLGlCQUFvQztRQUZwQyxtQkFBYyxHQUFkLGNBQWMsQ0FBZ0I7UUFDOUIsZ0JBQVcsR0FBWCxXQUFXLENBQWlDO1FBQzVDLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7SUFDM0MsQ0FBQztJQUVKLEtBQUssQ0FBQyxJQUFJO1FBQ1IsTUFBTSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVELDRCQUE0QjtJQUVwQixVQUFVLENBQUMsUUFBZ0I7UUFDakMsT0FBTyxHQUFHLGtCQUFrQixHQUFHLFFBQVEsRUFBRSxDQUFDO0lBQzVDLENBQUM7SUFFTyxXQUFXLENBQUMsR0FBVztRQUM3QixPQUFPLEdBQUcsaUJBQWlCLEdBQUcsR0FBRyxFQUFFLENBQUM7SUFDdEMsQ0FBQztJQUVPLEtBQUssQ0FBQyxXQUFXO1FBQ3ZCLE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUNwRSxJQUFJLENBQUMs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
@@ -0,0 +1,189 @@
1
+ import type * as interfaces from '../../dist_ts_interfaces/index.js';
2
+ import type { ConnectionManager } from './connectionmanager.js';
3
+ import type { ActionLog } from './actionlog.js';
4
+ import type { StorageManager } from '../storage/index.js';
5
+ /**
6
+ * Manages sync configurations and executes periodic git mirror operations.
7
+ * Each sync config defines a source → target connection mapping.
8
+ * Repos are mirrored using bare git repos stored on disk.
9
+ */
10
+ export declare class SyncManager {
11
+ private storageManager;
12
+ private connectionManager;
13
+ private actionLog;
14
+ private configs;
15
+ private timers;
16
+ private runningSync;
17
+ private syncedGroupMeta;
18
+ private currentSyncConfig;
19
+ private avatarUploadCache;
20
+ private activeGitChildren;
21
+ private stopping;
22
+ private mirrorsPath;
23
+ constructor(storageManager: StorageManager, connectionManager: ConnectionManager, actionLog: ActionLog);
24
+ init(): Promise<void>;
25
+ stop(): Promise<void>;
26
+ getConfigs(): interfaces.data.ISyncConfig[];
27
+ getConfig(id: string): interfaces.data.ISyncConfig | undefined;
28
+ createConfig(data: {
29
+ name: string;
30
+ sourceConnectionId: string;
31
+ targetConnectionId: string;
32
+ targetGroupOffset?: string;
33
+ intervalMinutes?: number;
34
+ enforceDelete?: boolean;
35
+ enforceGroupDelete?: boolean;
36
+ addMirrorHint?: boolean;
37
+ useGroupAvatarsForProjects?: boolean;
38
+ }): Promise<interfaces.data.ISyncConfig>;
39
+ updateConfig(id: string, updates: {
40
+ name?: string;
41
+ targetGroupOffset?: string;
42
+ intervalMinutes?: number;
43
+ enforceDelete?: boolean;
44
+ enforceGroupDelete?: boolean;
45
+ addMirrorHint?: boolean;
46
+ useGroupAvatarsForProjects?: boolean;
47
+ }): Promise<interfaces.data.ISyncConfig>;
48
+ deleteConfig(id: string): Promise<void>;
49
+ pauseConfig(id: string, paused: boolean): Promise<interfaces.data.ISyncConfig>;
50
+ getRepoStatuses(syncConfigId: string): Promise<interfaces.data.ISyncRepoStatus[]>;
51
+ previewSync(configId: string): Promise<{
52
+ mappings: Array<{
53
+ sourceFullPath: string;
54
+ targetFullPath: string;
55
+ }>;
56
+ deletions: string[];
57
+ groupDeletions: string[];
58
+ }>;
59
+ executeSync(configId: string, force?: boolean): Promise<void>;
60
+ private syncRepo;
61
+ private ensureTargetExists;
62
+ private ensureGitLabTarget;
63
+ private ensureGiteaTarget;
64
+ private enforceDeleteStaleRepos;
65
+ private enforceDeleteStaleGroups;
66
+ /**
67
+ * Move a GitLab group to the obsolete group with a unique suffix.
68
+ * Transfers the entire group (including subgroups and projects).
69
+ */
70
+ private moveGroupToObsolete;
71
+ /**
72
+ * Move all repos in a Gitea org to obsolete, then delete the empty org.
73
+ * Gitea orgs can't be transferred, so we move repos individually.
74
+ */
75
+ private moveGiteaOrgToObsolete;
76
+ /**
77
+ * Returns true if the given full path belongs to an obsolete namespace.
78
+ * Matches path segments named "obsolete" or ending with "-obsolete".
79
+ */
80
+ private isObsoletePath;
81
+ private buildAuthUrl;
82
+ private computeRelativePath;
83
+ /**
84
+ * Reverse-map a target group path to the corresponding source group path.
85
+ * Returns null if the target path is part of the offset itself (not a source-derived group).
86
+ */
87
+ private reverseTargetGroupPath;
88
+ private computeTargetFullPath;
89
+ /**
90
+ * Validates that the sync config's targetGroupOffset is reachable
91
+ * by the target connection's groupFilter. Throws when enforceDelete
92
+ * is on and the offset is outside the filter scope.
93
+ */
94
+ private validateSyncConfig;
95
+ /**
96
+ * Download binary data (e.g. avatar image) with provider auth headers.
97
+ * Returns null on 404 or error.
98
+ */
99
+ private rawBinaryFetch;
100
+ /**
101
+ * Raw multipart call for avatar uploads (GitLab requires multipart FormData).
102
+ */
103
+ private rawMultipartCall;
104
+ /**
105
+ * Normalize visibility values between GitLab and Gitea.
106
+ * GitLab: "public" | "internal" | "private"
107
+ * Gitea: "public" | "limited" | "private"
108
+ */
109
+ private normalizeVisibility;
110
+ /**
111
+ * Guess MIME type from binary content or URL for avatar uploads.
112
+ */
113
+ private guessAvatarMimeType;
114
+ /**
115
+ * Pre-push: ensure target's default_branch matches source so --prune won't delete it.
116
+ */
117
+ private syncDefaultBranchBeforePush;
118
+ /**
119
+ * Unprotect branches on the target that no longer exist in the source,
120
+ * so that git push --prune can delete them.
121
+ */
122
+ private unprotectStaleBranches;
123
+ /**
124
+ * Sync project metadata (description, visibility, topics, default_branch, avatar)
125
+ * from source to target after the git push.
126
+ */
127
+ private syncProjectMetadata;
128
+ /**
129
+ * Sync group/org metadata (description, visibility, avatar) from source to target.
130
+ */
131
+ private syncGroupMetadata;
132
+ private fetchProjectRaw;
133
+ private fetchGroupRaw;
134
+ private extractProjectMeta;
135
+ private extractGroupMeta;
136
+ private updateProjectMeta;
137
+ private updateGroupMeta;
138
+ private syncProjectAvatar;
139
+ private removeProjectAvatar;
140
+ private syncGroupAvatar;
141
+ private removeGroupAvatar;
142
+ private binaryEqual;
143
+ private hashBytes;
144
+ private uint8ArrayToBase64;
145
+ /**
146
+ * Raw HTTP call for API endpoints not supported by the client libraries.
147
+ */
148
+ private rawApiCall;
149
+ private generateSuffix;
150
+ /**
151
+ * Ensure an "obsolete" group/org exists under the target base path.
152
+ * Returns the obsolete group/org identifier needed for transfers.
153
+ */
154
+ private ensureObsoleteGroup;
155
+ /**
156
+ * Move a target repo to the "obsolete" group with a unique suffix.
157
+ * The project is also set to private.
158
+ */
159
+ private moveToObsolete;
160
+ /**
161
+ * Check whether the target remote in a bare mirror dir has unrelated history
162
+ * compared to the source (origin). Returns true if histories are completely disjoint.
163
+ */
164
+ private checkUnrelatedHistory;
165
+ private sanitizePath;
166
+ private dirExists;
167
+ /**
168
+ * Fetch all branch and tag SHAs from a repo via provider API.
169
+ * Returns null on any error (safe fallback to git-based comparison).
170
+ */
171
+ private listRefsViaProvider;
172
+ /**
173
+ * Compare refs between source and target via provider API (no git clone needed).
174
+ * Returns true (match), false (differ), or null (can't determine — fall through to git).
175
+ */
176
+ private refsMatchViaApi;
177
+ /**
178
+ * Compare local refs (source) with target remote refs.
179
+ * Returns true when all branches and tags are identical — no push needed.
180
+ */
181
+ private refsMatch;
182
+ private runGit;
183
+ private loadConfigs;
184
+ private persistConfig;
185
+ private updateRepoStatus;
186
+ private startTimer;
187
+ private stopTimer;
188
+ private waitForRunningSyncs;
189
+ }