@profoundlogic/coderflow-server 0.2.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 (202) hide show
  1. package/LICENSE.txt +322 -0
  2. package/README.md +158 -0
  3. package/dist/LICENSE.txt +322 -0
  4. package/dist/README.md +158 -0
  5. package/dist/base-image/Dockerfile +184 -0
  6. package/dist/base-image/agent-wrapper.sh +143 -0
  7. package/dist/base-image/apply-local-state.sh +357 -0
  8. package/dist/base-image/coder-git-credential-helper +307 -0
  9. package/dist/base-image/entrypoint.sh +942 -0
  10. package/dist/base-image/ssh_config_template +41 -0
  11. package/dist/base-image/start-code-server.sh +76 -0
  12. package/dist/base-image/sync-repos.sh +170 -0
  13. package/dist/base-image/vscode-extensions.txt +10 -0
  14. package/dist/base-image/vscode-settings.json +41 -0
  15. package/dist/coder-server.js +2 -0
  16. package/dist/config/cli-models.json +45 -0
  17. package/dist/config/imported-skills.schema.json +83 -0
  18. package/dist/config/skill-catalog.json +18 -0
  19. package/dist/config/skill-catalog.schema.json +140 -0
  20. package/dist/config.js +1 -0
  21. package/dist/examples/oidc.json.example +11 -0
  22. package/dist/lib/agent-keepalive.js +1 -0
  23. package/dist/lib/api-keys.js +1 -0
  24. package/dist/lib/apiKeys.js +1 -0
  25. package/dist/lib/auto-judge.js +1 -0
  26. package/dist/lib/basic-auth.js +1 -0
  27. package/dist/lib/build-history.js +1 -0
  28. package/dist/lib/build-output-service.js +1 -0
  29. package/dist/lib/build-scheduler.js +1 -0
  30. package/dist/lib/build-service.js +1 -0
  31. package/dist/lib/claude-oauth-refresh.js +1 -0
  32. package/dist/lib/cli/build.js +1 -0
  33. package/dist/lib/cli/config-command.js +1 -0
  34. package/dist/lib/cli/config.js +1 -0
  35. package/dist/lib/cli/create-user.js +1 -0
  36. package/dist/lib/cli/init.js +1 -0
  37. package/dist/lib/cli/jira.js +1 -0
  38. package/dist/lib/cli/license.js +1 -0
  39. package/dist/lib/cli/server-manager.js +1 -0
  40. package/dist/lib/container-tokens.js +1 -0
  41. package/dist/lib/data-dir.js +1 -0
  42. package/dist/lib/deployment-history.js +1 -0
  43. package/dist/lib/deployment-service.js +1 -0
  44. package/dist/lib/docker-utils.js +1 -0
  45. package/dist/lib/email.js +1 -0
  46. package/dist/lib/emailTemplates.js +1 -0
  47. package/dist/lib/entitlement.js +1 -0
  48. package/dist/lib/fetch-utils.js +1 -0
  49. package/dist/lib/git-provider-service.js +1 -0
  50. package/dist/lib/git-provider-setup/assets/coderflow_github_app.png +0 -0
  51. package/dist/lib/git-provider-setup/github-setup-handler.js +1 -0
  52. package/dist/lib/git-provider-setup/index.js +1 -0
  53. package/dist/lib/git-provider-setup/setup-factory.js +1 -0
  54. package/dist/lib/git-provider-setup/setup-interface.js +1 -0
  55. package/dist/lib/git-providers/azure-devops-provider.js +1 -0
  56. package/dist/lib/git-providers/github-app-provider.js +1 -0
  57. package/dist/lib/git-providers/index.js +1 -0
  58. package/dist/lib/git-providers/provider-factory.js +1 -0
  59. package/dist/lib/git-providers/provider-interface.js +1 -0
  60. package/dist/lib/jira-client.js +1 -0
  61. package/dist/lib/logger.js +1 -0
  62. package/dist/lib/model-fetcher.js +1 -0
  63. package/dist/lib/notifications.js +1 -0
  64. package/dist/lib/oidc-auth.js +1 -0
  65. package/dist/lib/oidc-device-flow.js +1 -0
  66. package/dist/lib/passwordTokens.js +1 -0
  67. package/dist/lib/pin-cascade.js +1 -0
  68. package/dist/lib/provider-accounts.js +1 -0
  69. package/dist/lib/provider-oauth.js +1 -0
  70. package/dist/lib/provider-profile.js +1 -0
  71. package/dist/lib/provider-token-refresh.js +1 -0
  72. package/dist/lib/roles.js +1 -0
  73. package/dist/lib/secrets.js +1 -0
  74. package/dist/lib/state-capture.js +1 -0
  75. package/dist/lib/static-files.js +1 -0
  76. package/dist/lib/task-name-generator.js +1 -0
  77. package/dist/lib/users.js +1 -0
  78. package/dist/middleware/requireAuth.js +1 -0
  79. package/dist/middleware/requireInit.js +1 -0
  80. package/dist/middleware/requirePermission.js +1 -0
  81. package/dist/package-lock.json +4151 -0
  82. package/dist/package.json +50 -0
  83. package/dist/routes/apiKeys.js +1 -0
  84. package/dist/routes/auth-oidc.js +1 -0
  85. package/dist/routes/auth.js +1 -0
  86. package/dist/routes/build.js +1 -0
  87. package/dist/routes/containers.js +1 -0
  88. package/dist/routes/deploy-task.js +1 -0
  89. package/dist/routes/environment-management.js +1 -0
  90. package/dist/routes/environments.js +1 -0
  91. package/dist/routes/external-skills.js +1 -0
  92. package/dist/routes/git-credentials.js +1 -0
  93. package/dist/routes/git-provider-setup.js +1 -0
  94. package/dist/routes/health.js +1 -0
  95. package/dist/routes/jira.js +1 -0
  96. package/dist/routes/objective-management.js +1 -0
  97. package/dist/routes/password.js +1 -0
  98. package/dist/routes/prompt.js +1 -0
  99. package/dist/routes/provider-auth.js +1 -0
  100. package/dist/routes/qa.js +1 -0
  101. package/dist/routes/settings.js +1 -0
  102. package/dist/routes/skill-management.js +1 -0
  103. package/dist/routes/skills.js +1 -0
  104. package/dist/routes/tasks.js +2 -0
  105. package/dist/routes/templates.js +1 -0
  106. package/dist/routes/test-task.js +1 -0
  107. package/dist/routes/test.js +1 -0
  108. package/dist/routes/users.js +1 -0
  109. package/dist/routes/visualizations.js +1 -0
  110. package/dist/schemas/template-metadata.schema.json +178 -0
  111. package/dist/scripts/create-user.js +2 -0
  112. package/dist/shipped-skills/environment-instructions/SKILL.md +154 -0
  113. package/dist/shipped-skills/environment-templates/SKILL.md +282 -0
  114. package/dist/shipped-skills/objective-management/SKILL.md +238 -0
  115. package/dist/shipped-skills/skill-editor/SKILL.md +326 -0
  116. package/dist/start.js +2 -0
  117. package/dist/web-ui/public/activity-detail-modal.js +1 -0
  118. package/dist/web-ui/public/activity-feed.js +1 -0
  119. package/dist/web-ui/public/activity-formatters.js +1 -0
  120. package/dist/web-ui/public/agent-event-parser.js +1 -0
  121. package/dist/web-ui/public/app.js +1 -0
  122. package/dist/web-ui/public/approve-dialog.js +1 -0
  123. package/dist/web-ui/public/coderflow-logo-reversed.svg +46 -0
  124. package/dist/web-ui/public/coderflow-logo.svg +46 -0
  125. package/dist/web-ui/public/comments-widget.js +1 -0
  126. package/dist/web-ui/public/docs/.nojekyll +0 -0
  127. package/dist/web-ui/public/docs/README.md +26 -0
  128. package/dist/web-ui/public/docs/_sidebar.md +47 -0
  129. package/dist/web-ui/public/docs/admin/ai-providers.md +132 -0
  130. package/dist/web-ui/public/docs/admin/email-notifications.md +69 -0
  131. package/dist/web-ui/public/docs/admin/environments.md +215 -0
  132. package/dist/web-ui/public/docs/admin/git-providers.md +147 -0
  133. package/dist/web-ui/public/docs/admin/installation.md +313 -0
  134. package/dist/web-ui/public/docs/admin/skills.md +35 -0
  135. package/dist/web-ui/public/docs/admin/sso.md +241 -0
  136. package/dist/web-ui/public/docs/admin/users-and-roles.md +57 -0
  137. package/dist/web-ui/public/docs/code/cli.md +102 -0
  138. package/dist/web-ui/public/docs/code/files-and-editing.md +86 -0
  139. package/dist/web-ui/public/docs/code/terminal-access.md +110 -0
  140. package/dist/web-ui/public/docs/code/vscode-extension.md +58 -0
  141. package/dist/web-ui/public/docs/getting-started/core-concepts.md +129 -0
  142. package/dist/web-ui/public/docs/getting-started/overview.md +46 -0
  143. package/dist/web-ui/public/docs/index.html +151 -0
  144. package/dist/web-ui/public/docs/integrations/custom.md +58 -0
  145. package/dist/web-ui/public/docs/integrations/ibmi/overview.md +58 -0
  146. package/dist/web-ui/public/docs/integrations/overview.md +48 -0
  147. package/dist/web-ui/public/docs/objectives/qa-mode.md +90 -0
  148. package/dist/web-ui/public/docs/objectives/staged-tasks.md +60 -0
  149. package/dist/web-ui/public/docs/objectives/working-with-objectives.md +102 -0
  150. package/dist/web-ui/public/docs/tasks/approval-and-deployment.md +83 -0
  151. package/dist/web-ui/public/docs/tasks/creating-tasks.md +111 -0
  152. package/dist/web-ui/public/docs/tasks/judging.md +114 -0
  153. package/dist/web-ui/public/docs/tasks/providing-feedback.md +41 -0
  154. package/dist/web-ui/public/docs/tasks/task-groups.md +73 -0
  155. package/dist/web-ui/public/docs/tasks/winner-selection.md +75 -0
  156. package/dist/web-ui/public/docs/templates/batch-processing.md +152 -0
  157. package/dist/web-ui/public/docs/templates/task-templates.md +44 -0
  158. package/dist/web-ui/public/docs/templates/template-examples.md +93 -0
  159. package/dist/web-ui/public/docs/testing/profound-automated-testing.md +77 -0
  160. package/dist/web-ui/public/docs/testing/task-visualizations.md +42 -0
  161. package/dist/web-ui/public/docs/testing/testing-menu.md +118 -0
  162. package/dist/web-ui/public/environments.css +3942 -0
  163. package/dist/web-ui/public/environments.html +1791 -0
  164. package/dist/web-ui/public/environments.js +1 -0
  165. package/dist/web-ui/public/favicon-16.png +0 -0
  166. package/dist/web-ui/public/favicon-32.png +0 -0
  167. package/dist/web-ui/public/favicon.ico +0 -0
  168. package/dist/web-ui/public/feedback-widget.css +3133 -0
  169. package/dist/web-ui/public/feedback-widget.js +1 -0
  170. package/dist/web-ui/public/git-history.css +2663 -0
  171. package/dist/web-ui/public/git-history.html +272 -0
  172. package/dist/web-ui/public/git-history.js +1 -0
  173. package/dist/web-ui/public/git-status.js +1 -0
  174. package/dist/web-ui/public/index.html +1459 -0
  175. package/dist/web-ui/public/index.js +1 -0
  176. package/dist/web-ui/public/login.html +346 -0
  177. package/dist/web-ui/public/login.js +1 -0
  178. package/dist/web-ui/public/markdown-editor.js +1 -0
  179. package/dist/web-ui/public/markdown-file-editor.js +1 -0
  180. package/dist/web-ui/public/modal-maximize.js +1 -0
  181. package/dist/web-ui/public/notifications.js +1 -0
  182. package/dist/web-ui/public/server-health.js +1 -0
  183. package/dist/web-ui/public/settings.css +761 -0
  184. package/dist/web-ui/public/settings.html +1044 -0
  185. package/dist/web-ui/public/settings.js +1 -0
  186. package/dist/web-ui/public/setup-password.html +355 -0
  187. package/dist/web-ui/public/setup-password.js +1 -0
  188. package/dist/web-ui/public/skills.css +1949 -0
  189. package/dist/web-ui/public/skills.html +820 -0
  190. package/dist/web-ui/public/skills.js +1 -0
  191. package/dist/web-ui/public/sse-client.js +1 -0
  192. package/dist/web-ui/public/sse-shared-worker.js +1 -0
  193. package/dist/web-ui/public/styles.css +18614 -0
  194. package/dist/web-ui/public/task.html +1779 -0
  195. package/dist/web-ui/public/task.js +1 -0
  196. package/dist/web-ui/public/terminal.html +45 -0
  197. package/dist/web-ui/public/terminal.js +1 -0
  198. package/dist/web-ui/public/theme.js +1 -0
  199. package/dist/web-ui/public/users.html +298 -0
  200. package/dist/web-ui/public/users.js +1 -0
  201. package/dist/web-ui/public/variant-grouping.js +1 -0
  202. package/package.json +63 -0
@@ -0,0 +1,307 @@
1
+ #!/bin/bash
2
+ # Git credential helper that fetches fresh tokens from server
3
+ # Only responds for repo URLs in CODER_MANAGED_REPOS; others fall through to store helper
4
+ #
5
+ # This helper is configured first in the credential helper chain:
6
+ # [credential]
7
+ # helper = /usr/local/bin/coder-git-credential-helper
8
+ # helper = store
9
+ #
10
+ # Behavior:
11
+ # - get: Check if URL is managed; if so, return credentials (from cache or server)
12
+ # If not managed, exit silently to fall through to store helper
13
+ # - store/erase: Ignore (we don't persist, store helper handles non-managed repos)
14
+
15
+ set -o pipefail
16
+
17
+ OPERATION="$1"
18
+ CACHE_DIR="/home/coder/.cache/coder-git-credentials"
19
+ CACHE_FILE="$CACHE_DIR/cache.json"
20
+ SERVER_URL="${CODER_CREDENTIAL_SERVER:-}"
21
+ CONTAINER_TOKEN="${CODER_CONTAINER_TOKEN:-}"
22
+ MANAGED_REPOS="${CODER_MANAGED_REPOS:-[]}"
23
+ CACHE_BUFFER_SECONDS=300 # Refresh 5 minutes before expiry
24
+
25
+ # Log function (only logs when CODER_CREDENTIAL_DEBUG is set)
26
+ debug_log() {
27
+ if [ -n "${CODER_CREDENTIAL_DEBUG:-}" ]; then
28
+ echo "[coder-git-credential-helper] $*" >&2
29
+ fi
30
+ }
31
+
32
+ # Normalize a URL for comparison (strip .git suffix, lowercase host)
33
+ normalize_url() {
34
+ local url="$1"
35
+ # Remove trailing .git
36
+ url="${url%.git}"
37
+ # Remove trailing slash
38
+ url="${url%/}"
39
+ # Lowercase the host part (everything up to the third slash)
40
+ # e.g., https://GITHUB.COM/owner/repo -> https://github.com/owner/repo
41
+ echo "$url" | sed -E 's|^(https?://[^/]+)|\L\1|'
42
+ }
43
+
44
+ # Check if a URL is in the managed repos list
45
+ is_managed_repo() {
46
+ local url="$1"
47
+ local normalized_url
48
+ normalized_url=$(normalize_url "$url")
49
+
50
+ # Check if URL is in MANAGED_REPOS array
51
+ # MANAGED_REPOS is a JSON array of URLs
52
+ if echo "$MANAGED_REPOS" | jq -e --arg url "$normalized_url" 'map(. | gsub("\\.git$"; "") | gsub("/$"; "")) | index($url) != null' > /dev/null 2>&1; then
53
+ return 0
54
+ fi
55
+ return 1
56
+ }
57
+
58
+ # Get cached credentials for a URL
59
+ get_cached_credentials() {
60
+ local url="$1"
61
+ local normalized_url
62
+ normalized_url=$(normalize_url "$url")
63
+
64
+ # Check if cache file exists
65
+ if [ ! -f "$CACHE_FILE" ]; then
66
+ return 1
67
+ fi
68
+
69
+ # Try to get cached entry for this URL
70
+ local cached_entry
71
+ cached_entry=$(jq -r --arg url "$normalized_url" '.[$url] // empty' "$CACHE_FILE" 2>/dev/null)
72
+
73
+ if [ -z "$cached_entry" ] || [ "$cached_entry" = "null" ]; then
74
+ debug_log "Cache miss for $normalized_url"
75
+ return 1
76
+ fi
77
+
78
+ # Check if cache is still valid (not expired)
79
+ local expires_at
80
+ expires_at=$(echo "$cached_entry" | jq -r '.expires_at // empty')
81
+
82
+ if [ -z "$expires_at" ]; then
83
+ debug_log "Cache entry missing expires_at for $normalized_url"
84
+ return 1
85
+ fi
86
+
87
+ # Convert ISO timestamp to epoch seconds
88
+ local expires_epoch
89
+ expires_epoch=$(date -d "$expires_at" +%s 2>/dev/null)
90
+
91
+ if [ -z "$expires_epoch" ]; then
92
+ debug_log "Failed to parse expires_at: $expires_at"
93
+ return 1
94
+ fi
95
+
96
+ local now_epoch
97
+ now_epoch=$(date +%s)
98
+
99
+ # Check if expired (with buffer)
100
+ local effective_expires=$((expires_epoch - CACHE_BUFFER_SECONDS))
101
+ if [ "$now_epoch" -ge "$effective_expires" ]; then
102
+ debug_log "Cache expired for $normalized_url (expires: $expires_at, buffer: ${CACHE_BUFFER_SECONDS}s)"
103
+ return 1
104
+ fi
105
+
106
+ # Cache is valid - extract credentials
107
+ local username password
108
+ username=$(echo "$cached_entry" | jq -r '.username // empty')
109
+ password=$(echo "$cached_entry" | jq -r '.password // empty')
110
+
111
+ if [ -z "$username" ] || [ -z "$password" ]; then
112
+ debug_log "Cache entry missing username or password for $normalized_url"
113
+ return 1
114
+ fi
115
+
116
+ debug_log "Cache hit for $normalized_url (expires: $expires_at)"
117
+ echo "$username"
118
+ echo "$password"
119
+ return 0
120
+ }
121
+
122
+ # Update cache with new credentials
123
+ update_cache() {
124
+ local url="$1"
125
+ local username="$2"
126
+ local password="$3"
127
+ local expires_at="$4"
128
+ local normalized_url
129
+ normalized_url=$(normalize_url "$url")
130
+
131
+ # Ensure cache directory exists with proper permissions
132
+ mkdir -p "$CACHE_DIR"
133
+ chmod 700 "$CACHE_DIR"
134
+
135
+ # Read existing cache or start fresh
136
+ local existing_cache="{}"
137
+ if [ -f "$CACHE_FILE" ]; then
138
+ existing_cache=$(cat "$CACHE_FILE" 2>/dev/null || echo "{}")
139
+ # Validate it's valid JSON
140
+ if ! echo "$existing_cache" | jq . > /dev/null 2>&1; then
141
+ existing_cache="{}"
142
+ fi
143
+ fi
144
+
145
+ # Add/update entry for this URL
146
+ local new_cache
147
+ new_cache=$(echo "$existing_cache" | jq --arg url "$normalized_url" \
148
+ --arg username "$username" \
149
+ --arg password "$password" \
150
+ --arg expires_at "$expires_at" \
151
+ '.[$url] = {username: $username, password: $password, expires_at: $expires_at}')
152
+
153
+ # Write to cache file with secure permissions
154
+ echo "$new_cache" > "$CACHE_FILE"
155
+ chmod 600 "$CACHE_FILE"
156
+
157
+ debug_log "Cache updated for $normalized_url (expires: $expires_at)"
158
+ }
159
+
160
+ # Fetch credentials from server
161
+ fetch_from_server() {
162
+ local url="$1"
163
+
164
+ # Check if server is configured
165
+ if [ -z "$SERVER_URL" ]; then
166
+ debug_log "No CODER_CREDENTIAL_SERVER configured"
167
+ return 1
168
+ fi
169
+
170
+ if [ -z "$CONTAINER_TOKEN" ]; then
171
+ debug_log "No CODER_CONTAINER_TOKEN configured"
172
+ return 1
173
+ fi
174
+
175
+ # URL-encode the repo URL for the query parameter
176
+ local encoded_url
177
+ encoded_url=$(printf '%s' "$url" | jq -sRr @uri)
178
+
179
+ local api_url="${SERVER_URL}/api/git/credentials?repo_url=${encoded_url}"
180
+
181
+ debug_log "Fetching credentials from: $api_url"
182
+
183
+ # Make HTTP request to server
184
+ local response http_code
185
+ response=$(curl -s -w "\n%{http_code}" \
186
+ -H "Authorization: Bearer $CONTAINER_TOKEN" \
187
+ -H "Accept: application/json" \
188
+ --connect-timeout 10 \
189
+ --max-time 30 \
190
+ "$api_url" 2>/dev/null)
191
+
192
+ # Extract HTTP status code (last line)
193
+ http_code=$(echo "$response" | tail -n1)
194
+ # Extract response body (all but last line)
195
+ response=$(echo "$response" | sed '$d')
196
+
197
+ if [ "$http_code" != "200" ]; then
198
+ debug_log "Server returned HTTP $http_code"
199
+ debug_log "Response: $response"
200
+ return 1
201
+ fi
202
+
203
+ # Parse response JSON
204
+ local username password expires_at
205
+ username=$(echo "$response" | jq -r '.username // empty')
206
+ password=$(echo "$response" | jq -r '.password // empty')
207
+ expires_at=$(echo "$response" | jq -r '.expires_at // empty')
208
+
209
+ if [ -z "$username" ] || [ -z "$password" ]; then
210
+ debug_log "Server response missing username or password"
211
+ return 1
212
+ fi
213
+
214
+ debug_log "Got credentials from server (expires: $expires_at)"
215
+
216
+ # Update cache with new credentials
217
+ if [ -n "$expires_at" ]; then
218
+ update_cache "$url" "$username" "$password" "$expires_at"
219
+ fi
220
+
221
+ echo "$username"
222
+ echo "$password"
223
+ return 0
224
+ }
225
+
226
+ # Handle 'get' operation
227
+ handle_get() {
228
+ local protocol="" host="" path_part=""
229
+
230
+ # Parse stdin (git credential protocol format)
231
+ while IFS='=' read -r key value; do
232
+ case "$key" in
233
+ protocol) protocol="$value" ;;
234
+ host) host="$value" ;;
235
+ path) path_part="$value" ;;
236
+ esac
237
+ done
238
+
239
+ debug_log "Received: protocol=$protocol host=$host path=$path_part"
240
+
241
+ # Validate we have required fields
242
+ if [ -z "$protocol" ] || [ -z "$host" ]; then
243
+ debug_log "Missing protocol or host, exiting"
244
+ exit 0
245
+ fi
246
+
247
+ # Reconstruct URL (strip .git suffix for matching)
248
+ local repo_url="${protocol}://${host}/${path_part%.git}"
249
+
250
+ debug_log "Reconstructed URL: $repo_url"
251
+
252
+ # Check if this repo is managed by us
253
+ if ! is_managed_repo "$repo_url"; then
254
+ debug_log "Not a managed repo, falling through to next helper"
255
+ exit 0
256
+ fi
257
+
258
+ debug_log "Repo is managed, looking for credentials"
259
+
260
+ # Try to get cached credentials
261
+ local cached_result
262
+ cached_result=$(get_cached_credentials "$repo_url")
263
+
264
+ if [ -n "$cached_result" ]; then
265
+ local username password
266
+ username=$(echo "$cached_result" | head -1)
267
+ password=$(echo "$cached_result" | tail -1)
268
+
269
+ echo "username=$username"
270
+ echo "password=$password"
271
+ exit 0
272
+ fi
273
+
274
+ # Cache miss - fetch from server
275
+ local server_result
276
+ server_result=$(fetch_from_server "$repo_url")
277
+
278
+ if [ -n "$server_result" ]; then
279
+ local username password
280
+ username=$(echo "$server_result" | head -1)
281
+ password=$(echo "$server_result" | tail -1)
282
+
283
+ echo "username=$username"
284
+ echo "password=$password"
285
+ exit 0
286
+ fi
287
+
288
+ # Failed to get credentials - exit silently to fall through
289
+ debug_log "Failed to get credentials, falling through to next helper"
290
+ exit 0
291
+ }
292
+
293
+ # Main operation switch
294
+ case "$OPERATION" in
295
+ get)
296
+ handle_get
297
+ ;;
298
+ store|erase)
299
+ # Ignore store/erase - we don't persist credentials
300
+ # The store helper in the chain handles non-managed repos
301
+ exit 0
302
+ ;;
303
+ *)
304
+ # Unknown operation - exit silently
305
+ exit 0
306
+ ;;
307
+ esac