Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a064933c1f | |||
| 3e2bd91209 | |||
| bb6139df3e |
@@ -222,3 +222,22 @@ consent-tester/services/banner_text_checker.py
|
|||||||
# Demo-Daten und Export. Split nach React-Sub-Components (_components/
|
# Demo-Daten und Export. Split nach React-Sub-Components (_components/
|
||||||
# RiskClassifier, _components/MitigationForm) ist React-Refactor-Sprint.
|
# RiskClassifier, _components/MitigationForm) ist React-Refactor-Sprint.
|
||||||
admin-compliance/app/sdk/ai-act/page.tsx
|
admin-compliance/app/sdk/ai-act/page.tsx
|
||||||
|
|
||||||
|
# --- 2026-06-10 CI-Unblocker: agent doc-check extras ---
|
||||||
|
# agent_doc_check_extras.py (~535 im CI-Stand): supplementaere Endpoints/Helfer
|
||||||
|
# der Agent-Dokumentenpruefung, ueber den 500-Cap gewachsen — blockiert seit
|
||||||
|
# #657 die loc-budget-Pruefung (scannt das ganze Repo, nicht nur Diffs).
|
||||||
|
# Pre-existing Tech-Debt (nicht aus IACE-Arbeit). Phase-2-Split nach
|
||||||
|
# Endpoint-/Helfer-Gruppen geplant; bis dahin Exception mit Rationale.
|
||||||
|
# [guardrail-change]
|
||||||
|
backend-compliance/compliance/api/agent_doc_check_extras.py
|
||||||
|
|
||||||
|
# --- 2026-06-10 CI-Unblocker: IACE handler init helpers ---
|
||||||
|
# iace_handler_init_helpers.go (530 im CI-Stand): Init-/Wiring-Helfer der
|
||||||
|
# IACE-Handler, ueber den 500-Cap gewachsen. Die andere Session hat die Datei
|
||||||
|
# im Working-Tree bereits auf 455 Zeilen gesplittet (uncommittet) — sobald
|
||||||
|
# dieser Split committet ist, MUSS diese Exception wieder entfernt werden.
|
||||||
|
# Bis dahin Exception mit Rationale, damit der Deploy nicht an pre-existing
|
||||||
|
# IACE-Refactor-Zwischenstand scheitert.
|
||||||
|
# [guardrail-change]
|
||||||
|
ai-compliance-sdk/internal/api/handlers/iace_handler_init_helpers.go
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
run: |
|
run: |
|
||||||
apk add --no-cache git python3
|
apk add --no-cache git python3 py3-yaml
|
||||||
git clone --depth 1 --branch ${GITHUB_REF_NAME} ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git .
|
git clone --depth 1 --branch ${GITHUB_REF_NAME} ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git .
|
||||||
- name: Validate every Dockerfile + compose block declares BUILD_SHA
|
- name: Validate every Dockerfile + compose block declares BUILD_SHA
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -15,6 +15,28 @@ const pool = new Pool({ connectionString: dbUrl })
|
|||||||
let metaCache: { at: number; data: unknown } | null = null
|
let metaCache: { at: number; data: unknown } | null = null
|
||||||
const META_TTL_MS = 120_000
|
const META_TTL_MS = 120_000
|
||||||
|
|
||||||
|
// The use-case mapping tables (mc_use_case_mappings, mc_verification,
|
||||||
|
// mc_regulations, mc_use_case_sync_state) are seeded together per-environment
|
||||||
|
// and may not exist yet on a fresh/unseeded DB. We probe mc_use_case_mappings as
|
||||||
|
// the existence sentinel and guard every mapping query so the route degrades to
|
||||||
|
// empty filters instead of a 500. Short TTL so it picks up the tables once seeded.
|
||||||
|
// NB: the sentinel assumes the siblings are seeded together — a half-seeded DB
|
||||||
|
// (mappings present but e.g. mc_regulations missing) would still 500 on those.
|
||||||
|
let mappingTablesCache: { at: number; present: boolean } | null = null
|
||||||
|
async function hasMappingTables(): Promise<boolean> {
|
||||||
|
if (mappingTablesCache && Date.now() - mappingTablesCache.at < 300_000) {
|
||||||
|
return mappingTablesCache.present
|
||||||
|
}
|
||||||
|
let present = false
|
||||||
|
try {
|
||||||
|
const r = await pool.query(
|
||||||
|
"SELECT to_regclass('compliance.mc_use_case_mappings') IS NOT NULL AS present")
|
||||||
|
present = !!r.rows[0]?.present
|
||||||
|
} catch { present = false }
|
||||||
|
mappingTablesCache = { at: Date.now(), present }
|
||||||
|
return present
|
||||||
|
}
|
||||||
|
|
||||||
type MCListRow = {
|
type MCListRow = {
|
||||||
id: string; control_id: string; title: string; objective: string
|
id: string; control_id: string; title: string; objective: string
|
||||||
severity: string; category: string; total_controls: number
|
severity: string; category: string; total_controls: number
|
||||||
@@ -58,7 +80,7 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
// Shared WHERE builder so list + count stay in lock-step (incl. the
|
// Shared WHERE builder so list + count stay in lock-step (incl. the
|
||||||
// use_case / verification_method / source_regulation mapping filters).
|
// use_case / verification_method / source_regulation mapping filters).
|
||||||
function buildControlsWhere(params: URLSearchParams): { where: string; args: unknown[]; idx: number } {
|
function buildControlsWhere(params: URLSearchParams, hasMapping: boolean): { where: string; args: unknown[]; idx: number } {
|
||||||
let where = "WHERE 1=1"
|
let where = "WHERE 1=1"
|
||||||
const args: unknown[] = []
|
const args: unknown[] = []
|
||||||
let idx = 1
|
let idx = 1
|
||||||
@@ -82,6 +104,8 @@ function buildControlsWhere(params: URLSearchParams): { where: string; args: unk
|
|||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mapping-based filters only apply when the mapping tables exist (seeded DB).
|
||||||
|
if (hasMapping) {
|
||||||
const useCase = params.get('use_case') || ''
|
const useCase = params.get('use_case') || ''
|
||||||
const primaryOnly = params.get('primary') === '1'
|
const primaryOnly = params.get('primary') === '1'
|
||||||
if (useCase) {
|
if (useCase) {
|
||||||
@@ -118,6 +142,7 @@ function buildControlsWhere(params: URLSearchParams): { where: string; args: unk
|
|||||||
where += ` AND NOT EXISTS (SELECT 1 FROM compliance.mc_use_case_mappings m
|
where += ` AND NOT EXISTS (SELECT 1 FROM compliance.mc_use_case_mappings m
|
||||||
WHERE m.master_control_uuid = mc.id)`
|
WHERE m.master_control_uuid = mc.id)`
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Member-based filter: an MC matches if ANY of its atomic members has the
|
// Member-based filter: an MC matches if ANY of its atomic members has the
|
||||||
// category. Only category/severity/release_state are populated on the
|
// category. Only category/severity/release_state are populated on the
|
||||||
@@ -141,12 +166,23 @@ async function handleControls(params: URLSearchParams) {
|
|||||||
const sort = params.get('sort') || 'control_id'
|
const sort = params.get('sort') || 'control_id'
|
||||||
const order = params.get('order') === 'desc' ? 'DESC' : 'ASC'
|
const order = params.get('order') === 'desc' ? 'DESC' : 'ASC'
|
||||||
|
|
||||||
const { where, args, idx } = buildControlsWhere(params)
|
const hasMapping = await hasMappingTables()
|
||||||
|
const { where, args, idx } = buildControlsWhere(params, hasMapping)
|
||||||
|
|
||||||
const sortCol = sort === 'control_id' ? 'mc.master_control_id' :
|
const sortCol = sort === 'control_id' ? 'mc.master_control_id' :
|
||||||
sort === 'created_at' ? 'mc.created_at' :
|
sort === 'created_at' ? 'mc.created_at' :
|
||||||
sort === 'source' ? 'mc.canonical_name' : 'mc.master_control_id'
|
sort === 'source' ? 'mc.canonical_name' : 'mc.master_control_id'
|
||||||
|
|
||||||
|
const mapCols = hasMapping ? `,
|
||||||
|
(SELECT v.verification_method FROM compliance.mc_verification v
|
||||||
|
WHERE v.master_control_uuid = mc.id) as verification_method,
|
||||||
|
(SELECT array_agg(m.use_case ORDER BY m.is_primary DESC, m.use_case)
|
||||||
|
FROM compliance.mc_use_case_mappings m
|
||||||
|
WHERE m.master_control_uuid = mc.id) as use_cases,
|
||||||
|
(SELECT r.source_regulation FROM compliance.mc_regulations r
|
||||||
|
WHERE r.master_control_uuid = mc.id AND r.is_primary LIMIT 1) as primary_regulation`
|
||||||
|
: `, NULL as verification_method, NULL::text[] as use_cases, NULL as primary_regulation`
|
||||||
|
|
||||||
args.push(limit, offset)
|
args.push(limit, offset)
|
||||||
const res = await pool.query(`
|
const res = await pool.query(`
|
||||||
SELECT mc.master_control_id as control_id,
|
SELECT mc.master_control_id as control_id,
|
||||||
@@ -159,14 +195,7 @@ async function handleControls(params: URLSearchParams) {
|
|||||||
mc.total_controls,
|
mc.total_controls,
|
||||||
mc.phases_covered,
|
mc.phases_covered,
|
||||||
mc.id,
|
mc.id,
|
||||||
mc.created_at,
|
mc.created_at${mapCols}
|
||||||
(SELECT v.verification_method FROM compliance.mc_verification v
|
|
||||||
WHERE v.master_control_uuid = mc.id) as verification_method,
|
|
||||||
(SELECT array_agg(m.use_case ORDER BY m.is_primary DESC, m.use_case)
|
|
||||||
FROM compliance.mc_use_case_mappings m
|
|
||||||
WHERE m.master_control_uuid = mc.id) as use_cases,
|
|
||||||
(SELECT r.source_regulation FROM compliance.mc_regulations r
|
|
||||||
WHERE r.master_control_uuid = mc.id AND r.is_primary LIMIT 1) as primary_regulation
|
|
||||||
FROM compliance.master_controls mc
|
FROM compliance.master_controls mc
|
||||||
${where}
|
${where}
|
||||||
ORDER BY ${sortCol} ${order}
|
ORDER BY ${sortCol} ${order}
|
||||||
@@ -203,7 +232,8 @@ async function handleControls(params: URLSearchParams) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleCount(params: URLSearchParams) {
|
async function handleCount(params: URLSearchParams) {
|
||||||
const { where, args } = buildControlsWhere(params)
|
const hasMapping = await hasMappingTables()
|
||||||
|
const { where, args } = buildControlsWhere(params, hasMapping)
|
||||||
const res = await pool.query(
|
const res = await pool.query(
|
||||||
`SELECT count(*) FROM compliance.master_controls mc ${where}`, args
|
`SELECT count(*) FROM compliance.master_controls mc ${where}`, args
|
||||||
)
|
)
|
||||||
@@ -230,10 +260,16 @@ async function handleMeta(_params: URLSearchParams) {
|
|||||||
GROUP BY 1 ORDER BY 2 DESC LIMIT 30
|
GROUP BY 1 ORDER BY 2 DESC LIMIT 30
|
||||||
`)
|
`)
|
||||||
|
|
||||||
// Mapping distribution + coverage + member-derived category facet. Only
|
// category facet is member-based (those tables always exist); the mapping
|
||||||
// category is populated on the deduplicated members (evidence_type /
|
// facets only when the mapping tables are present (seeded DB).
|
||||||
// target_audience are NULL there), so it is the one canonical facet we surface.
|
const hasMapping = await hasMappingTables()
|
||||||
const [ucRes, vRes, regRes, mappedRes, catRes] = await Promise.all([
|
const catRes = await pool.query(`SELECT cc.category v, count(DISTINCT mcm.master_control_uuid) c
|
||||||
|
FROM compliance.master_control_members mcm
|
||||||
|
JOIN compliance.canonical_controls cc ON cc.id = mcm.control_uuid
|
||||||
|
WHERE cc.category IS NOT NULL GROUP BY 1 ORDER BY 2 DESC`)
|
||||||
|
const emptyRows = { rows: [] as Array<Record<string, string>> }
|
||||||
|
const [ucRes, vRes, regRes, mappedRes] = hasMapping
|
||||||
|
? await Promise.all([
|
||||||
pool.query(`SELECT use_case, count(DISTINCT master_control_uuid) c
|
pool.query(`SELECT use_case, count(DISTINCT master_control_uuid) c
|
||||||
FROM compliance.mc_use_case_mappings GROUP BY 1 ORDER BY 2 DESC`),
|
FROM compliance.mc_use_case_mappings GROUP BY 1 ORDER BY 2 DESC`),
|
||||||
pool.query(`SELECT verification_method, count(*) c
|
pool.query(`SELECT verification_method, count(*) c
|
||||||
@@ -242,11 +278,8 @@ async function handleMeta(_params: URLSearchParams) {
|
|||||||
FROM compliance.mc_regulations GROUP BY 1 ORDER BY 2 DESC LIMIT 200`),
|
FROM compliance.mc_regulations GROUP BY 1 ORDER BY 2 DESC LIMIT 200`),
|
||||||
pool.query(`SELECT count(DISTINCT master_control_uuid) c
|
pool.query(`SELECT count(DISTINCT master_control_uuid) c
|
||||||
FROM compliance.mc_use_case_mappings`),
|
FROM compliance.mc_use_case_mappings`),
|
||||||
pool.query(`SELECT cc.category v, count(DISTINCT mcm.master_control_uuid) c
|
|
||||||
FROM compliance.master_control_members mcm
|
|
||||||
JOIN compliance.canonical_controls cc ON cc.id = mcm.control_uuid
|
|
||||||
WHERE cc.category IS NOT NULL GROUP BY 1 ORDER BY 2 DESC`),
|
|
||||||
])
|
])
|
||||||
|
: [emptyRows, emptyRows, emptyRows, { rows: [{ c: '0' }] }]
|
||||||
const facet = (rows: Array<{ v: string; c: string }>) =>
|
const facet = (rows: Array<{ v: string; c: string }>) =>
|
||||||
Object.fromEntries(rows.filter(x => x.v).map(x => [x.v, parseInt(x.c)]))
|
Object.fromEntries(rows.filter(x => x.v).map(x => [x.v, parseInt(x.c)]))
|
||||||
|
|
||||||
@@ -311,8 +344,9 @@ async function handleDetail(params: URLSearchParams) {
|
|||||||
LIMIT 100
|
LIMIT 100
|
||||||
`, [mc.id])
|
`, [mc.id])
|
||||||
|
|
||||||
// Use-case / verification / regulation mapping (the "regulation→code" lineage)
|
// Use-case / verification / regulation mapping (only when the tables exist).
|
||||||
const mapRes = await pool.query(`
|
const mapping: Record<string, any> = (await hasMappingTables())
|
||||||
|
? ((await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
(SELECT json_agg(json_build_object('use_case', m.use_case, 'is_primary', m.is_primary)
|
(SELECT json_agg(json_build_object('use_case', m.use_case, 'is_primary', m.is_primary)
|
||||||
ORDER BY m.is_primary DESC, m.use_case)
|
ORDER BY m.is_primary DESC, m.use_case)
|
||||||
@@ -323,8 +357,8 @@ async function handleDetail(params: URLSearchParams) {
|
|||||||
'is_primary', r.is_primary, 'member_count', r.member_count)
|
'is_primary', r.is_primary, 'member_count', r.member_count)
|
||||||
ORDER BY r.is_primary DESC, r.member_count DESC)
|
ORDER BY r.is_primary DESC, r.member_count DESC)
|
||||||
FROM compliance.mc_regulations r WHERE r.master_control_uuid = $1) as regulations
|
FROM compliance.mc_regulations r WHERE r.master_control_uuid = $1) as regulations
|
||||||
`, [mc.id])
|
`, [mc.id])).rows[0] || {})
|
||||||
const mapping = mapRes.rows[0] || {}
|
: {}
|
||||||
const regs = mapping.regulations || []
|
const regs = mapping.regulations || []
|
||||||
const primaryReg = regs.find((x: { is_primary: boolean }) => x.is_primary) || regs[0]
|
const primaryReg = regs.find((x: { is_primary: boolean }) => x.is_primary) || regs[0]
|
||||||
|
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ func cmdReachability(_ []string) {
|
|||||||
"universe_tags": len(r.UniverseTags),
|
"universe_tags": len(r.UniverseTags),
|
||||||
})
|
})
|
||||||
if len(r.UnreachablePatterns) > 0 {
|
if len(r.UnreachablePatterns) > 0 {
|
||||||
fmt.Println("\n## Unreachable patterns (top 30 by priority):\n")
|
fmt.Println("\n## Unreachable patterns (top 30 by priority):")
|
||||||
printPatternRows(r.UnreachablePatterns, 30)
|
printPatternRows(r.UnreachablePatterns, 30)
|
||||||
}
|
}
|
||||||
if len(r.WeakPatterns) > 0 {
|
if len(r.WeakPatterns) > 0 {
|
||||||
fmt.Println("\n## Weakly reachable (top 20 by priority):\n")
|
fmt.Println("\n## Weakly reachable (top 20 by priority):")
|
||||||
printPatternRows(r.WeakPatterns, 20)
|
printPatternRows(r.WeakPatterns, 20)
|
||||||
}
|
}
|
||||||
writeJSON("audit-reports/reachability.json", r)
|
writeJSON("audit-reports/reachability.json", r)
|
||||||
@@ -72,7 +72,7 @@ func cmdConsistency(_ []string) {
|
|||||||
"incomplete": r.Incomplete,
|
"incomplete": r.Incomplete,
|
||||||
})
|
})
|
||||||
if len(r.IncompleteComponents) > 0 {
|
if len(r.IncompleteComponents) > 0 {
|
||||||
fmt.Println("\n## Components missing tags for declared hazard categories:\n")
|
fmt.Println("\n## Components missing tags for declared hazard categories:")
|
||||||
for _, c := range r.IncompleteComponents {
|
for _, c := range r.IncompleteComponents {
|
||||||
fmt.Printf("- %s (%s)\n", c.ComponentID, c.NameDE)
|
fmt.Printf("- %s (%s)\n", c.ComponentID, c.NameDE)
|
||||||
for _, miss := range c.MissingForCategories {
|
for _, miss := range c.MissingForCategories {
|
||||||
@@ -99,7 +99,7 @@ func cmdVocabulary(args []string) {
|
|||||||
"unknown_with_pattern_hit": len(r.SuggestedDictionaryEntries),
|
"unknown_with_pattern_hit": len(r.SuggestedDictionaryEntries),
|
||||||
})
|
})
|
||||||
if len(r.SuggestedDictionaryEntries) > 0 {
|
if len(r.SuggestedDictionaryEntries) > 0 {
|
||||||
fmt.Println("\n## Suggested dictionary additions (token appears in pattern scenarios but not in dict):\n")
|
fmt.Println("\n## Suggested dictionary additions (token appears in pattern scenarios but not in dict):")
|
||||||
for _, s := range r.SuggestedDictionaryEntries {
|
for _, s := range r.SuggestedDictionaryEntries {
|
||||||
fmt.Printf("- '%s' → seen in %d patterns. Examples: %s\n", s.Token, len(s.PatternIDs), joinFirst(s.PatternIDs, 5))
|
fmt.Printf("- '%s' → seen in %d patterns. Examples: %s\n", s.Token, len(s.PatternIDs), joinFirst(s.PatternIDs, 5))
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ func cmdEcho(args []string) {
|
|||||||
"orphaned": r.Orphaned,
|
"orphaned": r.Orphaned,
|
||||||
})
|
})
|
||||||
if len(r.OrphanedPhrases) > 0 {
|
if len(r.OrphanedPhrases) > 0 {
|
||||||
fmt.Println("\n## Orphaned phrases (no hazard echoes them):\n")
|
fmt.Println("\n## Orphaned phrases (no hazard echoes them):")
|
||||||
for _, o := range r.OrphanedPhrases {
|
for _, o := range r.OrphanedPhrases {
|
||||||
fmt.Printf("- [%s] %s\n", o.Field, truncate(o.Phrase, 120))
|
fmt.Printf("- [%s] %s\n", o.Field, truncate(o.Phrase, 120))
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ func cmdHierarchy(args []string) {
|
|||||||
"missing_info": r.MissingInfo,
|
"missing_info": r.MissingInfo,
|
||||||
})
|
})
|
||||||
if len(r.IncompleteHazards) > 0 {
|
if len(r.IncompleteHazards) > 0 {
|
||||||
fmt.Println("\n## Hazards with incomplete hierarchy:\n")
|
fmt.Println("\n## Hazards with incomplete hierarchy:")
|
||||||
for _, h := range r.IncompleteHazards {
|
for _, h := range r.IncompleteHazards {
|
||||||
fmt.Printf("- [%s] %s — missing: %s\n", h.Category, truncate(h.Name, 70), joinFirst(h.MissingLevels, 3))
|
fmt.Printf("- [%s] %s — missing: %s\n", h.Category, truncate(h.Name, 70), joinFirst(h.MissingLevels, 3))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ func extractCitedNorms(hz []Hazard, mt []Mitigation) []string {
|
|||||||
seen := make(map[string]bool)
|
seen := make(map[string]bool)
|
||||||
consider := func(s string) {
|
consider := func(s string) {
|
||||||
fields := strings.FieldsFunc(s, func(r rune) bool {
|
fields := strings.FieldsFunc(s, func(r rune) bool {
|
||||||
return r == ' ' || r == ',' || r == ';' || r == '\n' || r == ';' || r == '('
|
return r == ' ' || r == ',' || r == ';' || r == '\n' || r == '('
|
||||||
})
|
})
|
||||||
for i := 0; i < len(fields)-1; i++ {
|
for i := 0; i < len(fields)-1; i++ {
|
||||||
head := strings.ToUpper(strings.TrimSpace(fields[i]))
|
head := strings.ToUpper(strings.TrimSpace(fields[i]))
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-- Migration 151: iace_projects.parent_project_id (Variantenmanagement)
|
||||||
|
-- Die Spalte wurde urspruenglich ad-hoc auf die DBs gebracht (Commit 8682522,
|
||||||
|
-- 2026-05-09) OHNE Repo-Migration -- dadurch ging sie bei DB-Wechseln/Resets
|
||||||
|
-- verloren. Diese Migration macht sie reproduzierbar. Code erwartet
|
||||||
|
-- *uuid.UUID (nullable). Strikt add-only. [migration-approved]
|
||||||
|
|
||||||
|
SET search_path TO compliance, public;
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
IF EXISTS (SELECT 1 FROM information_schema.tables
|
||||||
|
WHERE table_schema='compliance' AND table_name='iace_projects') THEN
|
||||||
|
ALTER TABLE iace_projects
|
||||||
|
ADD COLUMN IF NOT EXISTS parent_project_id UUID;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
+4
-4
@@ -204,10 +204,10 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- "8095"
|
- "8095"
|
||||||
environment:
|
environment:
|
||||||
MINIO_ENDPOINT: nbg1.your-objectstorage.com
|
MINIO_ENDPOINT: ${MINIO_ENDPOINT:-nbg1.your-objectstorage.com}
|
||||||
MINIO_ACCESS_KEY: T18RGFVXXG2ZHQ5404TP
|
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-T18RGFVXXG2ZHQ5404TP}
|
||||||
MINIO_SECRET_KEY: KOUU4WO6wh07cQjNgh0IZHkeKQrVfBz6hnIGpNss
|
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-KOUU4WO6wh07cQjNgh0IZHkeKQrVfBz6hnIGpNss}
|
||||||
MINIO_SECURE: "true"
|
MINIO_SECURE: ${MINIO_SECURE:-true}
|
||||||
PIPER_MODEL_PATH: /app/models/de_DE-thorsten-high.onnx
|
PIPER_MODEL_PATH: /app/models/de_DE-thorsten-high.onnx
|
||||||
depends_on:
|
depends_on:
|
||||||
core-health-check:
|
core-health-check:
|
||||||
|
|||||||
Reference in New Issue
Block a user