fix(deploy): déléguer le redéploiement du dashboard à l hôte

This commit is contained in:
Manus AI
2026-08-18 08:17:06 +00:00
parent abba8e352a
commit fe0a81fc98
10 changed files with 2583 additions and 4 deletions

View File

@@ -25,10 +25,10 @@ RUN apk add --no-cache docker-cli docker-cli-compose git curl unzip bash openssh
RUN git config --global user.email "admin@santinova-soft.org" && \
git config --global user.name "Manus Dashboard"
# Copy backend
COPY backend/package.json ./backend/
# Installer les dépendances backend depuis un verrou versionné pour un build déterministe.
COPY backend/package.json backend/package-lock.json ./backend/
WORKDIR /app/backend
RUN npm install --production
RUN npm ci --omit=dev
COPY backend/ ./

2483
src/backend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"test": "node test/app-registry.test.js && node test/healthcheck.test.js"
"test": "node test/app-registry.test.js && node test/healthcheck.test.js && node test/webhook.test.js"
},
"dependencies": {
"express": "^4.21.0",

View File

@@ -17,10 +17,33 @@ const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || '';
const APPS_BASE_PATH = process.env.APPS_BASE_PATH || '/opt/manus-deploy/apps';
const DEPLOY_SCRIPT = '/opt/manus-deploy/scripts/deploy-app.sh';
const LOG_DIR = '/var/log/manus-deploy';
const DASHBOARD_APP_ID = 'manus-dashboard';
const DASHBOARD_DEPLOY_REQUEST = path.join(APPS_BASE_PATH, DASHBOARD_APP_ID, '.deployment-request');
// Déploiements en cours (évite les doubles déclenchements)
const deployingApps = new Set();
/**
* Le conteneur ne peut pas se recréer lui-même : Docker interrompt son client
* `docker compose` au moment où le conteneur courant est arrêté. Ce cas est
* donc délégué au service systemd hôte manus-dashboard-self-deploy.path.
*/
function isHostManagedDeployment(appName) {
return appName === DASHBOARD_APP_ID;
}
function requestDashboardHostDeployment({ branch, commitHash, committer }) {
const temporaryRequest = `${DASHBOARD_DEPLOY_REQUEST}.${process.pid}.tmp`;
const request = {
branch,
commitHash,
committer,
requestedAt: new Date().toISOString(),
};
fs.writeFileSync(temporaryRequest, JSON.stringify(request, null, 2), { mode: 0o600 });
fs.renameSync(temporaryRequest, DASHBOARD_DEPLOY_REQUEST);
}
function verifyGiteaSignature(req) {
if (!WEBHOOK_SECRET) {
console.warn('[Webhook] AVERTISSEMENT: WEBHOOK_SECRET non défini. Validation désactivée.');
@@ -103,6 +126,15 @@ router.post('/gitea', (req, res) => {
if (!appName) return res.status(200).json({ message: `Dépôt ${repoName} non déployé ou sans manifeste valide` });
if (branch !== 'main') return res.status(200).json({ message: `Branch ${branch} ignorée` });
if (isHostManagedDeployment(appName)) {
requestDashboardHostDeployment({ branch, commitHash, committer });
return res.status(202).json({
message: 'Redéploiement du dashboard confié au service hôte',
commit: commitHash,
branch,
});
}
res.status(202).json({ message: `Déploiement de ${appName} déclenché`, commit: commitHash, branch, committer });
// Récupérer la fonction broadcast si disponible globalement
@@ -135,3 +167,4 @@ router.get('/status', (req, res) => {
});
module.exports = router;
module.exports.isHostManagedDeployment = isHostManagedDeployment;

View File

@@ -0,0 +1,11 @@
/*
* Un conteneur ne peut pas recréer fiablement son propre conteneur Docker :
* le client `docker compose` est arrêté en même temps que lui. Le webhook doit
* donc déléguer ce cas précis à un service systemd hôte.
*/
const assert = require('node:assert/strict');
const { isHostManagedDeployment } = require('../src/webhook');
assert.equal(isHostManagedDeployment('manus-dashboard'), true);
assert.equal(isHostManagedDeployment('itinova-contacts'), false);
console.log('OK webhook');