@inetafrica/open-claudia 2.2.8 → 2.2.9
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.
- package/CHANGELOG.md +3 -0
- package/package.json +1 -1
- package/web.js +51 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2.2.9
|
|
4
|
+
- Startup self-heal for grandfathered AgentSpace pods: if `.password-changed` exists on the PVC but AgentSpace was never notified (because the pod changed its password before `AGENTSPACE_API_URL` was injected, or before the `/pods/self/password-changed` callback shipped), the web server fires the callback once on startup and writes a `.password-changed-notified` sentinel so subsequent restarts don't retry. `notifyAgentSpacePasswordChanged` now returns a status so `setPassword` can also drop the sentinel after a successful live notification. Pre-v2.2.x grandfathered pods that never wrote the marker file still need manual `webPasswordUserSet=true` in Mongo.
|
|
5
|
+
|
|
3
6
|
## v2.2.8
|
|
4
7
|
- `/upgrade` now works on docker containers that run our baked-in `/app` source (the common self-host layout). Previously the handler fell through to `npm install -g`, which hit `EACCES` because the runtime user is uid 1001 and couldn't write the global node_modules — and even when it could, the bot reads from `/app`, not the global root, so the new version was never picked up. The new branch detects the `/app` layout, `npm pack`s the latest tarball, overlays it onto `/app`, runs `npm install --omit=dev`, and exits so the orchestrator restarts the container on the new source. AgentSpace pods (which have `AGENTSPACE_POD_TOKEN` + `AGENTSPACE_API_URL`) still go through the control plane; nothing else changes for them or for npm-global installs.
|
|
5
8
|
- Dockerfile: `chown -R claudia:claudia /app` after the build steps so the runtime user can overlay new source during the in-place `/upgrade` above. Previously `/app` and its `node_modules` were root-owned because the COPY and `npm ci` ran as root before `USER 1001`.
|
package/package.json
CHANGED
package/web.js
CHANGED
|
@@ -31,6 +31,10 @@ function getPassword() {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const PASSWORD_CHANGED_FILE = path.join(CONFIG_DIR, ".password-changed");
|
|
34
|
+
// Sentinel: written once AgentSpace has been notified about the user-set
|
|
35
|
+
// password. Used to keep the startup self-heal idempotent for grandfathered
|
|
36
|
+
// pods that changed their password before AGENTSPACE_API_URL was injected.
|
|
37
|
+
const PASSWORD_CHANGED_NOTIFIED_FILE = path.join(CONFIG_DIR, ".password-changed-notified");
|
|
34
38
|
|
|
35
39
|
function isPasswordChanged() {
|
|
36
40
|
return fs.existsSync(PASSWORD_CHANGED_FILE);
|
|
@@ -48,30 +52,56 @@ function validatePasswordComplexity(pw) {
|
|
|
48
52
|
function setPassword(newPassword) {
|
|
49
53
|
fs.writeFileSync(WEB_PASSWORD_FILE, newPassword);
|
|
50
54
|
fs.writeFileSync(PASSWORD_CHANGED_FILE, new Date().toISOString());
|
|
51
|
-
notifyAgentSpacePasswordChanged()
|
|
55
|
+
notifyAgentSpacePasswordChanged().then((r) => {
|
|
56
|
+
if (r && r.ok) {
|
|
57
|
+
try { fs.writeFileSync(PASSWORD_CHANGED_NOTIFIED_FILE, new Date().toISOString()); } catch (e) {}
|
|
58
|
+
}
|
|
59
|
+
}).catch(() => {});
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
function notifyAgentSpacePasswordChanged() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
const apiUrl = process.env.AGENTSPACE_API_URL;
|
|
65
|
+
const token = process.env.AGENTSPACE_POD_TOKEN;
|
|
66
|
+
if (!apiUrl || !token) return resolve({ ok: false, reason: "missing-env" });
|
|
67
|
+
let u;
|
|
68
|
+
try { u = new URL("/pods/self/password-changed", apiUrl); } catch (e) { return resolve({ ok: false, reason: "bad-url" }); }
|
|
69
|
+
const lib = u.protocol === "https:" ? require("https") : require("http");
|
|
70
|
+
const req = lib.request({
|
|
71
|
+
method: "POST",
|
|
72
|
+
hostname: u.hostname,
|
|
73
|
+
port: u.port || (u.protocol === "https:" ? 443 : 80),
|
|
74
|
+
path: u.pathname + u.search,
|
|
75
|
+
headers: {
|
|
76
|
+
"Authorization": `Bearer ${token}`,
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
"Content-Length": "0",
|
|
79
|
+
},
|
|
80
|
+
}, (res) => {
|
|
81
|
+
res.on("data", () => {});
|
|
82
|
+
res.on("end", () => resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, status: res.statusCode }));
|
|
83
|
+
});
|
|
84
|
+
req.on("error", (e) => resolve({ ok: false, reason: String(e.message || e) }));
|
|
85
|
+
req.setTimeout(5000, () => { try { req.destroy(); } catch (e) {} resolve({ ok: false, reason: "timeout" }); });
|
|
86
|
+
req.end();
|
|
71
87
|
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Startup self-heal for grandfathered pods. If the pod changed its web
|
|
91
|
+
// password before AGENTSPACE_API_URL was injected (or before the callback
|
|
92
|
+
// existed), the marker file is on disk but AgentSpace still thinks the
|
|
93
|
+
// initial password is valid. Fire the callback once on startup; on success
|
|
94
|
+
// write a sentinel so we don't repeat it on every restart.
|
|
95
|
+
function reconcileGrandfatheredPasswordChange() {
|
|
96
|
+
if (!isPasswordChanged()) return;
|
|
97
|
+
if (fs.existsSync(PASSWORD_CHANGED_NOTIFIED_FILE)) return;
|
|
98
|
+
if (!process.env.AGENTSPACE_API_URL || !process.env.AGENTSPACE_POD_TOKEN) return;
|
|
99
|
+
notifyAgentSpacePasswordChanged().then((r) => {
|
|
100
|
+
if (r && r.ok) {
|
|
101
|
+
try { fs.writeFileSync(PASSWORD_CHANGED_NOTIFIED_FILE, new Date().toISOString()); } catch (e) {}
|
|
102
|
+
console.log("[web] Notified AgentSpace of pre-existing user-set password.");
|
|
103
|
+
}
|
|
104
|
+
}).catch(() => {});
|
|
75
105
|
}
|
|
76
106
|
|
|
77
107
|
function checkBearerAuth(req) {
|
|
@@ -741,6 +771,7 @@ function startWebServer() {
|
|
|
741
771
|
server.listen(PORT, () => {
|
|
742
772
|
console.log(`Web UI running on http://localhost:${PORT}`);
|
|
743
773
|
console.log("Admin password configured.");
|
|
774
|
+
reconcileGrandfatheredPasswordChange();
|
|
744
775
|
});
|
|
745
776
|
|
|
746
777
|
return server;
|