Skip to content
Merged

170 #63

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ jobs:
- name: Build frontend
run: npm run build:frontend

clean-install:
# What a user gets from the source archive: only tracked files, an empty npm
# cache, no prior node_modules. Fails on lockfile drift or integrity errors.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Install from an exported tree with a cold cache
run: |
export_dir="$(mktemp -d)"
git archive HEAD | tar -x -C "$export_dir"
cd "$export_dir"
npm_config_cache="$(mktemp -d)" npm ci --ignore-scripts --no-audit --no-fund

postgres-suite:
# The migration, transaction and upgrade tests that only run when a real
# PostgreSQL server is reachable. Without this job they are skipped
Expand Down
45 changes: 32 additions & 13 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,24 @@ concurrency:
cancel-in-progress: false

jobs:
verify-source-install:
# The tagged tree must install cleanly from an empty cache before any image
# is published, so the source archive is as buildable as the images.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Install from an exported tree with a cold cache
run: |
export_dir="$(mktemp -d)"
git archive HEAD | tar -x -C "$export_dir"
cd "$export_dir"
npm_config_cache="$(mktemp -d)" npm ci --ignore-scripts --no-audit --no-fund

build-and-publish:
needs: verify-source-install
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -29,6 +46,17 @@ jobs:
attestations: write
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Extract release metadata
Expand Down Expand Up @@ -69,15 +97,6 @@ jobs:
with:
name: release-evidence-${{ matrix.profile }}-${{ matrix.arch }}
path: artifacts/*.json
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Push the verified image to both registries without rebuilding
id: push
run: |
Expand Down Expand Up @@ -119,11 +138,11 @@ jobs:
run: |
version="${GITHUB_REF_NAME#v}"
for image in "${REGISTRY}/${IMAGE_NAME}" "${DOCKERHUB_IMAGE}"; do
core_tags=(--tag "$image:$version" --tag "$image:sha-${GITHUB_SHA:0:7}")
batteries_tags=(--tag "$image:batteries-$version" --tag "$image:batteries-sha-${GITHUB_SHA:0:7}")
core_tags=(--tag "$image:$version")
batteries_tags=(--tag "$image:batteries-$version")
if [[ "$version" != *-* ]]; then
core_tags+=(--tag "$image:${version%.*}" --tag "$image:${version%%.*}" --tag "$image:latest")
batteries_tags+=(--tag "$image:batteries-${version%.*}" --tag "$image:batteries-${version%%.*}" --tag "$image:batteries")
core_tags+=(--tag "$image:latest")
batteries_tags+=(--tag "$image:batteries")
fi
docker buildx imagetools create "${core_tags[@]}" \
"$image:${GITHUB_REF_NAME}-amd64" "$image:${GITHUB_REF_NAME}-arm64"
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# Changelog

## [1.6.1] - 2026-10-29

### Security

- Dependency refresh in the reviewed lockfile (`@azure/identity` 4.14.0,
`body-parser` 2.4.0 and 1.20.9, `fast-uri`, `iconv-lite` and others).
- `@azure/msal-node` is pinned to 7.1.1 through an npm override to clear
GHSA-xcx6-jx8p-x3h5 (fixed in 7.1.0), which `@azure/identity` 4.14.0 does not
yet allow through its own `^6.0.0` range.
- `zod` moves to 4.6.7 to clear GHSA-mrhx-c7xc-m3w5. Backend schemas import
`zod/v3`, so validation behaviour is unchanged.
- `npm audit --omit=dev` reports no vulnerabilities.

### Fixed

- Version metadata is consistent across the packages, lockfile, OpenAPI
document, Helm chart, image labels, health endpoint and UI header.

### Release process

- Release images are tagged only `<version>`, `latest`, `batteries-<version>`
and `batteries`. The major, minor and commit-SHA tag families are no longer
published; `latest` and `batteries` move only on stable releases. Pin to
`<version>` for reproducible deployments.
- CI and the release workflow install the tagged tree from a `git archive`
export with an empty npm cache (`npm ci --ignore-scripts`). Image publishing
waits for this check, so a lockfile that does not install cleanly from the
source archive blocks the release.

## [1.6.0] - 2026-10-22

### Added
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ ARG BUILDPLATFORM
# Add metadata labels
LABEL org.opencontainers.image.title="Pabawi Core"
LABEL org.opencontainers.image.description="Pabawi infrastructure management web interface"
LABEL org.opencontainers.image.version="1.6.0"
LABEL org.opencontainers.image.version="1.6.1"
LABEL org.opencontainers.image.vendor="example42"
LABEL org.opencontainers.image.source="https://github.com/example42/pabawi"

Expand All @@ -91,7 +91,7 @@ RUN apt-get update && \
apt-get install -y --no-install-recommends \
bash \
ca-certificates \
&& apt-get install -y --only-upgrade libpcre2-8-0 \
&& apt-get install -y --only-upgrade libpcre2-8-0 perl-base \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.alpine
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ ARG BUILDPLATFORM
# Add metadata labels
LABEL org.opencontainers.image.title="Pabawi"
LABEL org.opencontainers.image.description="Puppet Ansible Bolt Awesome Web Interface"
LABEL org.opencontainers.image.version="1.6.0"
LABEL org.opencontainers.image.version="1.6.1"
LABEL org.opencontainers.image.vendor="example42"
LABEL org.opencontainers.image.source="https://github.com/example42/pabawi"

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.ubuntu
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ ARG BUILDPLATFORM
# Add metadata labels
LABEL org.opencontainers.image.title="Pabawi"
LABEL org.opencontainers.image.description="Puppet Ansible Bolt Awesome Web Interface"
LABEL org.opencontainers.image.version="1.6.0"
LABEL org.opencontainers.image.version="1.6.1"
LABEL org.opencontainers.image.vendor="example42"
LABEL org.opencontainers.image.source="https://github.com/example42/pabawi"

Expand Down
4 changes: 2 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "backend",
"version": "1.6.0",
"version": "1.6.1",
"description": "Backend API server for Pabawi",
"main": "dist/server.js",
"scripts": {
Expand Down Expand Up @@ -34,7 +34,7 @@
"ssh2": "^1.17.0",
"ws": "^8.21.0",
"yaml": "^2.8.2",
"zod": "^3.23.8"
"zod": "^4.6.7"
},
"devDependencies": {
"@types/bcrypt": "^5.0.2",
Expand Down
2 changes: 1 addition & 1 deletion backend/src/config/ConfigService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
type EntraIdConfig,
type WhitelistConfig,
} from "./schema";
import { z } from "zod";
import { z } from "zod/v3";
import { parseJson } from "../utils/json";
import { LoggerService } from "../services/LoggerService";

Expand Down
2 changes: 1 addition & 1 deletion backend/src/config/ldap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { isIP } from 'node:net';
import { X509Certificate } from 'node:crypto';
import { parseLdapDn } from './ldapDn';
import { parseLdapFilter } from './ldapFilter';
import { z } from 'zod';
import { z } from "zod/v3";

const attribute = z.string().regex(/^(?:[a-zA-Z][a-zA-Z0-9-]*|[0-9]+(?:\.[0-9]+)+)$/);
const hostname = z.string().max(253).refine(value =>
Expand Down
2 changes: 1 addition & 1 deletion backend/src/config/schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LdapConfigSchema } from "./ldap";
export { LdapConfigSchema, type LdapConfig } from "./ldap";
import { z } from "zod";
import { z } from "zod/v3";

/**
* Command whitelist configuration schema
Expand Down
2 changes: 1 addition & 1 deletion backend/src/integrations/ssh/hostTrust.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createHash } from 'node:crypto';
import { readFileSync } from 'node:fs';
import { z } from 'zod';
import { z } from "zod/v3";

const fingerprintMap = z.record(z.array(z.string().regex(/^SHA256:[A-Za-z0-9+/]{43}$/)).min(1));

Expand Down
2 changes: 1 addition & 1 deletion backend/src/mcp/McpServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type { HieraPlugin } from '../integrations/hiera/HieraPlugin';
import type { PuppetDBService } from '../integrations/puppetdb/PuppetDBService';
import type { PuppetRunHistoryService } from '../services/PuppetRunHistoryService';
import type { LoggerService } from '../services/LoggerService';
import type { ZodTypeAny } from 'zod';
import type { ZodTypeAny } from "zod/v3";
import { registerAllTools } from './McpToolHandlers';

// MCP SDK uses package.json "exports" which requires moduleResolution >= node16.
Expand Down
2 changes: 1 addition & 1 deletion backend/src/mcp/McpToolHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { redactText } from '../shared/diagnosticRedaction';
* Requirements: 11–18, 19.1–19.4, 14.1–14.6
*/

import { z } from 'zod';
import { z } from "zod/v3";
import type { McpDependencies, McpServerInstance } from './McpServer';
import { TOOL_PERMISSIONS } from './McpServer';
import {
Expand Down
4 changes: 2 additions & 2 deletions backend/src/routes/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PermissionService } from "../services/PermissionService";
import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import { asyncHandler } from "./asyncHandler";
import { FederatedAccountError, UserService } from "../services/UserService";
import { SetupService } from "../services/SetupService";
Expand All @@ -16,7 +16,7 @@ import {
isDuplicateError,
extractDuplicateField
} from "../utils/errorHandling";
import { ZodError } from "zod";
import { ZodError } from "zod/v3";
import { createAuthMiddleware } from "../middleware/authMiddleware";
import { type DIContainer, createDefaultContainer, resolveAuthenticationService } from "../container/DIContainer";
import type { EntraIdService } from "../services/EntraIdService";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/commands.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import { type ExecutionService, ExecutionLifecycleError } from "../services/ExecutionService";
import { ExecutionQueueFullError } from "../services/ExecutionQueue";
import type { BoltCommandWhitelistService } from "../validation/CommandWhitelistService";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/console.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";

import type { DatabaseAdapter } from "../database/DatabaseAdapter";
import type { IntegrationManager } from "../integrations/IntegrationManager";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/crashDumps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { readDiagnosticFile, retainedDiagnosticFiles } from "../utils/diagnostic
import { Router, type Request, type Response } from "express";
import fs from "node:fs";
import path from "node:path";
import { z } from "zod";
import { z } from "zod/v3";
import { asyncHandler } from "./asyncHandler";
import type { DIContainer } from "../container/DIContainer";

Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { redactDiagnostics } from '../shared/diagnosticRedaction';
*/

import { Router, type Request, type Response } from 'express';
import { z } from 'zod';
import { z } from "zod/v3";
import { asyncHandler } from './asyncHandler';
import type { DIContainer } from '../container/DIContainer';

Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/entraIdAuth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from "node:assert/strict";
import { randomBytes } from "node:crypto";
import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import { asyncHandler } from "./asyncHandler";
import { type EntraIdService, EntraIdError, ENTRA_ID_ERROR_CODES } from "../services/EntraIdService";
import type { DatabaseService } from "../database/DatabaseService";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/executions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type ExecutionService, ExecutionLifecycleError } from "../services/ExecutionService";
import { ExecutionDispatchError } from "../services/ExecutionDispatcher";
import { Router, type Request, type Response, type RequestHandler } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import type {
ExecutionRepository,
ExecutionType,
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/facts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Router, type Request, type Response, type RequestHandler } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import type { IntegrationManager } from "../integrations/IntegrationManager";
import {
BoltNodeUnreachableError,
Expand Down
4 changes: 2 additions & 2 deletions backend/src/routes/groups.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import assert from "node:assert/strict";
import { AuditLoggingService } from "../services/AuditLoggingService";
import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import { asyncHandler } from "./asyncHandler";
import { GroupService } from "../services/GroupService";
import { PermissionService } from "../services/PermissionService";
import type { DatabaseService } from "../database/DatabaseService";
import { sendValidationError, ERROR_CODES } from "../utils/errorHandling";
import { ZodError } from "zod";
import { ZodError } from "zod/v3";
import { createAuthMiddleware } from "../middleware/authMiddleware";
import { createRbacMiddleware } from "../middleware/rbacMiddleware";
import { type DIContainer, createDefaultContainer, resolveAuthenticationService } from "../container/DIContainer";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/hiera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import type { IntegrationManager } from "../integrations/IntegrationManager";
import type { HieraPlugin } from "../integrations/hiera/HieraPlugin";
import {
Expand Down
4 changes: 2 additions & 2 deletions backend/src/routes/integrations/aws.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Router, type Request, type RequestHandler, type Response } from "express";
import { z } from "zod";
import { ZodError } from "zod";
import { z } from "zod/v3";
import { ZodError } from "zod/v3";
import { asyncHandler } from "../asyncHandler";
import type { AWSPlugin } from "../../integrations/aws/AWSPlugin";
import type { IntegrationManager } from "../../integrations/IntegrationManager";
Expand Down
4 changes: 2 additions & 2 deletions backend/src/routes/integrations/azure.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Router, type Request, type RequestHandler, type Response } from "express";
import { z } from "zod";
import { ZodError } from "zod";
import { z } from "zod/v3";
import { ZodError } from "zod/v3";
import { asyncHandler } from "../asyncHandler";
import type { AzurePlugin } from "../../integrations/azure/AzurePlugin";
import type { IntegrationManager } from "../../integrations/IntegrationManager";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/integrations/monitoring.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { PermissionMiddlewareFactory } from "../../middleware/routeAuthorization";
import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import type { IntegrationManager } from "../../integrations/IntegrationManager";
import type { CheckmkPlugin } from "../../integrations/checkmk/CheckmkPlugin";
import { asyncHandler } from "../asyncHandler";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/integrations/monitoringActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*/

import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import type { IntegrationManager } from "../../integrations/IntegrationManager";
import type { CheckmkPlugin } from "../../integrations/checkmk/CheckmkPlugin";
import type { DatabaseService } from "../../database/DatabaseService";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/integrations/monitoringOverview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/

import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import type { IntegrationManager } from "../../integrations/IntegrationManager";
import type { CheckmkPlugin } from "../../integrations/checkmk/CheckmkPlugin";
import { asyncHandler } from "../asyncHandler";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/integrations/proxmox.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import type { IntegrationManager } from "../../integrations/IntegrationManager";
import type { ProxmoxIntegration } from "../../integrations/proxmox/ProxmoxIntegration";
import { asyncHandler } from "../asyncHandler";
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/integrations/puppetdb.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Router, type Request, type Response } from "express";
import { z } from "zod";
import { z } from "zod/v3";
import type { PuppetDBService } from "../../integrations/puppetdb/PuppetDBService";
import {
PuppetDBConnectionError,
Expand Down
Loading
Loading