Compare commits

..
Author SHA1 Message Date
Kilian eed67f3a4f Bump chart version to 0.115.0 2026-06-15 18:28:23 +02:00
59 changed files with 388 additions and 9495 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.167.3
version: 0.115.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
+14 -1233
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,431 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"
/>
<meta name="description" content="Kerberos.io Mailing">
<style type="text/css">
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-Regular.woff?v=/dist/fonts/Inter-Regular.woff2?v=3.183.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-Regular.woff?v=/dist/fonts/Inter-Regular.woff2?v=3.183.18") format("woff");
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-Medium.woff2?v=3.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-Medium.woff?v=3.18") format("woff");
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-SemiBold.woff2?v=3.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-SemiBold.woff?v=3.18") format("woff");
}
@font-face {
font-family: 'Inter var';
font-weight: 100 900;
font-display: swap;
font-style: normal;
font-named-instance: 'Regular';
src: url("https://kerberos.io/dist/fonts/Inter-roman.var.woff2?v=3.18") format("woff2");
}
body{
background: #E5E5E5;
margin-top:0;
margin-bottom: 0;
margin-right: 0;
margin-left: 0;
padding-top: 0;
padding-left: 0;
padding-right: 0;
padding-bottom: 0;
font-family: 'Inter';
}
a, a:hover, a:active {
color: #262424;
text-decoration: none;
}
.corner-td{
width: 60px;
}
table {border-collapse:separate;max-width: 850px; margin: 0 auto; width: 100%;}
.ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td {line-height: 100%;}
.ExternalClass {width: 100%;}
@media screen and (max-width:500px){
.tab-td{
padding-left: 10px!important;
}
.tab-td a h4{
font-size: 14px!important;
}
.corner-td{
width: 20px!important;
}
.company-name-td h3{
font-size: 16px!important;
}
table.header-table{
padding-top: 8px!important;
padding-right: 0px!important;
padding-bottom: 24px!important;
padding-left: 0px!important;
}
.colored-card-td h4{
font-size: 14px!important;
}
.colored-card-td h2{
font-size: 20px!important;
}
.colored-card-td a p{
font-size: 12px!important;
width: 143px!important;
}
.colored-card-td{
padding-top: 24px!important;
padding-right: 24px!important;
padding-bottom: 24px!important;
padding-left: 24px!important;
}
.colorless-card-td{
padding-top: 24px!important;
padding-right: 24px!important;
padding-bottom: 24px!important;
padding-left: 24px!important;
}
.colorless-card-td h3{
font-size: 18px!important;
}
.colorless-card-td p{
font-size: 14px!important;
}
.colorless-card-table{
margin-left: 0px!important;
margin-right: 0px!important;
margin-top: 24px!important;
margin-bottom: 24px!important;
}
.footer-td{
display: table-row!important;
}
}
@media screen and (max-width:600px) {
.footer-td{
display: table-row!important;
}
}
@media screen and (max-width:650px) {
.footer-table{
margin-left: 0px!important;
margin-right: 0px!important;
margin-top: 0px!important;
margin-bottom: 36px!important;
}
}
</style>
</head>
<body height="100%" width="100%">
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="36" class="header-table" style="padding-top: 36px ;padding-right: 0;padding-bottom: 36px;padding-left: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td width="48" height="36" align="left"><img alt="Kerberos.io" width="36" height="36" src="https://kerberos.io/images/email/kerberos.png"/></td>
<td height="36" align="left" class="company-name-td">
<h3 width="36" height="36" style=" font-family: Inter;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #262424;">Kerberos.io</h3>
</td>
<td height="36" width="36" style="padding-left: 36px;" class="tab-td" align="right">
<a style="text-decoration: none;color: none;" href={{tab1_href}}>
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: right;
color: #6D6666;">{{tab1_title}}</h4>
</a>
</td>
<td height="36" width="36" style="padding-left: 36px;" class="tab-td" align="right" >
<a style="text-decoration: none;color: none;" href={{tab2_href}}>
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: right;
color: #6D6666;">{{tab2_title}}</h4>
</a>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td class="colored-card-td" bgcolor="#57356B" style="padding-left: 48px;padding-right: 48px;padding-top: 48px;padding-bottom: 48px;border-radius: 4px;background-color:#57356B;">
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#b09fb9;">Hey, {{user}}</h4>
<h2 style=" font-family: Inter;
font-size: 24px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#FFFFFF;
padding-top: 12px;
margin-bottom: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;">Several of your cameras changed status</h2>
<h2 style=" font-family: Inter;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#FFFFFF;
padding-top: 0;
padding-bottom: 24px;
padding-left: 0;
padding-right: 0;
color:#b09fb9;">{{text}}</h2>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" class="colorless-card-table" style="margin-top: 36px;margin-bottom: 36px;margin-left: 0;margin-right: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td class="colorless-card-td" bgcolor="#FFFFFF" style="background-color:#FFFFFF;padding-top: 36px;padding-right: 43px;padding-bottom: 25px;padding-left: 43px;border-radius: 4px;">
<h3 style=" font-family: Inter;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #262424;
width: 480px">What changed</h3>
{{sections}}
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #6D6666;
margin-top: 12px;">Cameras that go offline together usually share a cause, such as a site losing its internet connection or power. Have a look into your Kerberos Hub account for the latest recordings and the status of your cameras.</p>
<a style="text-decoration: none;color: none;" href="{{link}}">
<p style="font-family: Inter;
font-size: 14px;
font-style: normal;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#FFFFFF;
background-color: #84559F;
padding-top: 6px;
padding-bottom: 6px;
padding-right: 16px;
padding-left: 16px;
width: 160px;
border-radius: 4px;
text-align: center;
cursor: pointer;">Go to Kerberos Hub -></p>
</a>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" class="footer-table" style="margin-top: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;display:table-row !important">
<![endif]-->
<td height="146" width="190" class="footer-td" style="margin-bottom: 12px;" valign="top" align="left">
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td>
<h4 style=" font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#6D6666;">Get in touch</h4>
<a style="text-decoration: none;color: none;" href="mailto:support@verstraeten.io">
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 16px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">support@kerberos.io</p>
</a>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 16px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">9000 Ghent, BE</p>
<a style="text-decoration: none;color: none;" href="https://kerberos.io/">
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">https://kerberos.io</p>
</a>
</td>
</tr>
</tbody>
</table>
</td>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;display:table-row !important">
<![endif]-->
<td class="footer-td" style="border-radius: 4px;padding-left: 0;padding-right: 0;padding-top: 0;padding-bottom: 0; margin-bottom: 12px;" valign="top" align="left">
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td>
<h4 style=" font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#6D6666;">About Kerberos</h4>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">Welcome to the revolutionary video analytics and video management platform. Open, modular, and extensible for everyone, anywhere.</p>
<p style="margin-top: 12px;">
<a href="https://twitter.com/kerberosio" style="text-decoration: none;color: none;">
<img width="24" height="24" alt="Twitter" src="https://kerberos.io/images/email/twitter.png"/>
</a>
<a href="https://reddit.com/r/kerberos_io" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Reddit" src="https://kerberos.io/images/email/reddit.png"/>
</a>
<a href="https://www.youtube.com/channel/UCnd9q7iRNNw4W95eQwQuECA" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Youtube" src="https://kerberos.io/images/email/youtube.png"/>
</a>
<a href="https://github.com/kerberos-io" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Github" src="https://kerberos.io/images/email/github.png"/>
</a>
</p>
</td>
</tr>
</tbody>
</table>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr style="height: 50px">
<td></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</body>
</html>
@@ -1,22 +0,0 @@
Kerberos.io
------------
Hey, {{user}}
Several of your cameras changed status
{{text}}
{{sectionsText}}
Go to Kerberos Hub ->
{{link}}
Get in touch
------------
support@kerberos.io
9000 Ghent, BE
https://kerberos.io
About Kerberos
------------
Welcome to the revolutionary video analytics and video management platform. Open, modular, and extensible for everyone, anywhere.
@@ -1,418 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"
/>
<meta name="description" content="Kerberos.io Mailing">
<style type="text/css">
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-Regular.woff?v=/dist/fonts/Inter-Regular.woff2?v=3.183.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-Regular.woff?v=/dist/fonts/Inter-Regular.woff2?v=3.183.18") format("woff");
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-Medium.woff2?v=3.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-Medium.woff?v=3.18") format("woff");
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-SemiBold.woff2?v=3.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-SemiBold.woff?v=3.18") format("woff");
}
@font-face {
font-family: 'Inter var';
font-weight: 100 900;
font-display: swap;
font-style: normal;
font-named-instance: 'Regular';
src: url("https://kerberos.io/dist/fonts/Inter-roman.var.woff2?v=3.18") format("woff2");
}
body{
background: #E5E5E5;
margin-top:0;
margin-bottom: 0;
margin-right: 0;
margin-left: 0;
padding-top: 0;
padding-left: 0;
padding-right: 0;
padding-bottom: 0;
font-family: 'Inter';
}
a, a:hover, a:active {
color: #262424;
text-decoration: none;
}
.corner-td{
width: 60px;
}
table {border-collapse:separate;max-width: 850px; margin: 0 auto; width: 100%;}
.ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td {line-height: 100%;}
.ExternalClass {width: 100%;}
@media screen and (max-width:500px){
.tab-td{
padding-left: 10px!important;
}
.tab-td a h4{
font-size: 14px!important;
}
.corner-td{
width: 20px!important;
}
.company-name-td h3{
font-size: 16px!important;
}
table.header-table{
padding-top: 8px!important;
padding-right: 0px!important;
padding-bottom: 24px!important;
padding-left: 0px!important;
}
.colored-card-td h4{
font-size: 14px!important;
}
.colored-card-td h2{
font-size: 20px!important;
}
.colored-card-td a p{
font-size: 12px!important;
width: 143px!important;
}
.colored-card-td{
padding-top: 24px!important;
padding-right: 24px!important;
padding-bottom: 24px!important;
padding-left: 24px!important;
}
.colorless-card-td{
padding-top: 24px!important;
padding-right: 24px!important;
padding-bottom: 24px!important;
padding-left: 24px!important;
}
.colorless-card-td h3{
font-size: 18px!important;
}
.colorless-card-td p{
font-size: 14px!important;
}
.colorless-card-table{
margin-left: 0px!important;
margin-right: 0px!important;
margin-top: 24px!important;
margin-bottom: 24px!important;
}
.footer-td{
display: table-row!important;
}
}
@media screen and (max-width:600px) {
.footer-td{
display: table-row!important;
}
}
@media screen and (max-width:650px) {
.footer-table{
margin-left: 0px!important;
margin-right: 0px!important;
margin-top: 0px!important;
margin-bottom: 36px!important;
}
}
</style>
</head>
<body height="100%" width="100%">
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="36" class="header-table" style="padding-top: 36px ;padding-right: 0;padding-bottom: 36px;padding-left: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td width="48" height="36" align="left"><img alt="Kerberos.io" width="36" height="36" src="https://kerberos.io/images/email/kerberos.png"/></td>
<td height="36" align="left" class="company-name-td">
<h3 width="36" height="36" style=" font-family: Inter;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #262424;">Kerberos.io</h3>
</td>
<td height="36" width="36" style="padding-left: 36px;" class="tab-td" align="right">
<a style="text-decoration: none;color: none;" href={{tab1_href}}>
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: right;
color: #6D6666;">{{tab1_title}}</h4>
</a>
</td>
<td height="36" width="36" style="padding-left: 36px;" class="tab-td" align="right" >
<a style="text-decoration: none;color: none;" href={{tab2_href}}>
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: right;
color: #6D6666;">{{tab2_title}}</h4>
</a>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td class="colored-card-td" bgcolor="#57356B" style="padding-left: 48px;padding-right: 48px;padding-top: 48px;padding-bottom: 48px;border-radius: 4px;background-color:#57356B;">
<h2 style=" font-family: Inter;
font-size: 24px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#FFFFFF;
padding-top: 12px;
margin-bottom: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;">A case has been shared with you</h2>
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#b09fb9;">{{user}} shared a case with you</h4>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" class="colorless-card-table" style="margin-top: 36px;margin-bottom: 36px;margin-left: 0;margin-right: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td class="colorless-card-td" bgcolor="#FFFFFF" style="background-color:#FFFFFF;padding-top: 36px;padding-right: 43px;padding-bottom: 25px;padding-left: 43px;border-radius: 4px;">
<h3 style=" font-family: Inter;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #262424;
width: 280px">Open the shared case</h3>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #6D6666;
margin-top: 12px;">{{user}} has shared a case with you. Click the button below to open it. You'll be asked to request a one-time verification code from the share page itself.<br/><br/>This link will expire in {{expiry}}.</p>
<a style="text-decoration: none;color: none;" href="{{url}}">
<p style="font-family: Inter;
font-size: 14px;
font-style: normal;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#FFFFFF;
background-color: #84559F;
padding-top: 6px;
padding-bottom: 6px;
padding-right: 16px;
padding-left: 16px;
width: 130px;
border-radius: 4px;
text-align: center;
cursor: pointer;">Open case -></p>
</a>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" class="footer-table" style="margin-top: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;display:table-row !important">
<![endif]-->
<td height="146" width="190" class="footer-td" style="margin-bottom: 12px;" valign="top" align="left">
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td>
<h4 style=" font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#6D6666;">Get in touch</h4>
<a style="text-decoration: none;color: none;" href="mailto:support@kerberos.io">
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 16px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">support@kerberos.io</p>
</a>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 16px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">9000 Ghent, BE</p>
<a style="text-decoration: none;color: none;" href="https://kerberos.io/">
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">https://kerberos.io</p>
</a>
</td>
</tr>
</tbody>
</table>
</td>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;display:table-row !important">
<![endif]-->
<td class="footer-td" style="border-radius: 4px;padding-left: 0;padding-right: 0;padding-top: 0;padding-bottom: 0; margin-bottom: 12px;" valign="top" align="left">
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td>
<h4 style=" font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#6D6666;">About Kerberos</h4>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">Welcome to the revolutionary video analytics and video management platform. Open, modular, and extensible for everyone, anywhere.</p>
<p style="margin-top: 12px;">
<a href="https://twitter.com/kerberosio" style="text-decoration: none;color: none;">
<img width="24" height="24" alt="Twitter" src="https://kerberos.io/images/email/twitter.png"/>
</a>
<a href="https://reddit.com/r/kerberos_io" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Reddit" src="https://kerberos.io/images/email/reddit.png"/>
</a>
<a href="https://www.youtube.com/channel/UCnd9q7iRNNw4W95eQwQuECA" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Youtube" src="https://kerberos.io/images/email/youtube.png"/>
</a>
<a href="https://github.com/kerberos-io" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Github" src="https://kerberos.io/images/email/github.png"/>
</a>
</p>
</td>
</tr>
</tbody>
</table>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr style="height: 50px">
<td></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</body>
</html>
@@ -1,21 +0,0 @@
Kerberos.io
------------
A case has been shared with you
{{user}} shared a case with you
Open the shared case
{{user}} has shared a case with you. Open the link below to access it — you'll be asked to request a one-time verification code from the share page.
{{url}}
This link will expire in {{expiry}}.
Get in touch
------------
support@kerberos.io
9000 Ghent, BE
https://kerberos.io
About Kerberos
------------
Welcome to the revolutionary video analytics and video management platform. Open, modular, and extensible for everyone, anywhere.
@@ -1,425 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"
/>
<meta name="description" content="Kerberos.io Mailing">
<style type="text/css">
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-Regular.woff?v=/dist/fonts/Inter-Regular.woff2?v=3.183.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-Regular.woff?v=/dist/fonts/Inter-Regular.woff2?v=3.183.18") format("woff");
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-Medium.woff2?v=3.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-Medium.woff?v=3.18") format("woff");
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url("https://kerberos.io/dist/fonts/Inter-SemiBold.woff2?v=3.18") format("woff2"),
url("https://kerberos.io/dist/fonts/Inter-SemiBold.woff?v=3.18") format("woff");
}
@font-face {
font-family: 'Inter var';
font-weight: 100 900;
font-display: swap;
font-style: normal;
font-named-instance: 'Regular';
src: url("https://kerberos.io/dist/fonts/Inter-roman.var.woff2?v=3.18") format("woff2");
}
body{
background: #E5E5E5;
margin-top:0;
margin-bottom: 0;
margin-right: 0;
margin-left: 0;
padding-top: 0;
padding-left: 0;
padding-right: 0;
padding-bottom: 0;
font-family: 'Inter';
}
a, a:hover, a:active {
color: #262424;
text-decoration: none;
}
.corner-td{
width: 60px;
}
table {border-collapse:separate;max-width: 850px; margin: 0 auto; width: 100%;}
.ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td {line-height: 100%;}
.ExternalClass {width: 100%;}
@media screen and (max-width:500px){
.tab-td{
padding-left: 10px!important;
}
.tab-td a h4{
font-size: 14px!important;
}
.corner-td{
width: 20px!important;
}
.company-name-td h3{
font-size: 16px!important;
}
table.header-table{
padding-top: 8px!important;
padding-right: 0px!important;
padding-bottom: 24px!important;
padding-left: 0px!important;
}
.colored-card-td h4{
font-size: 14px!important;
}
.colored-card-td h2{
font-size: 20px!important;
}
.colored-card-td a p{
font-size: 12px!important;
width: 143px!important;
}
.colored-card-td{
padding-top: 24px!important;
padding-right: 24px!important;
padding-bottom: 24px!important;
padding-left: 24px!important;
}
.colorless-card-td{
padding-top: 24px!important;
padding-right: 24px!important;
padding-bottom: 24px!important;
padding-left: 24px!important;
}
.colorless-card-td h3{
font-size: 18px!important;
}
.colorless-card-td p{
font-size: 14px!important;
}
.colorless-card-table{
margin-left: 0px!important;
margin-right: 0px!important;
margin-top: 24px!important;
margin-bottom: 24px!important;
}
.footer-td{
display: table-row!important;
}
}
@media screen and (max-width:600px) {
.footer-td{
display: table-row!important;
}
}
@media screen and (max-width:650px) {
.footer-table{
margin-left: 0px!important;
margin-right: 0px!important;
margin-top: 0px!important;
margin-bottom: 36px!important;
}
}
</style>
</head>
<body height="100%" width="100%">
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="36" class="header-table" style="padding-top: 36px ;padding-right: 0;padding-bottom: 36px;padding-left: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td width="48" height="36" align="left"><img alt="Kerberos.io" width="36" height="36" src="https://kerberos.io/images/email/kerberos.png"/></td>
<td height="36" align="left" class="company-name-td">
<h3 width="36" height="36" style=" font-family: Inter;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #262424;">Kerberos.io</h3>
</td>
<td height="36" width="36" style="padding-left: 36px;" class="tab-td" align="right">
<a style="text-decoration: none;color: none;" href={{tab1_href}}>
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: right;
color: #6D6666;">{{tab1_title}}</h4>
</a>
</td>
<td height="36" width="36" style="padding-left: 36px;" class="tab-td" align="right" >
<a style="text-decoration: none;color: none;" href={{tab2_href}}>
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: right;
color: #6D6666;">{{tab2_title}}</h4>
</a>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td class="colored-card-td" bgcolor="#57356B" style="padding-left: 48px;padding-right: 48px;padding-top: 48px;padding-bottom: 48px;border-radius: 4px;background-color:#57356B;">
<h2 style=" font-family: Inter;
font-size: 24px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#FFFFFF;
padding-top: 12px;
margin-bottom: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;">Verify your access</h2>
<h4 style="font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#b09fb9;">Use the code below to open the shared case</h4>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" class="colorless-card-table" style="margin-top: 36px;margin-bottom: 36px;margin-left: 0;margin-right: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<td class="colorless-card-td" bgcolor="#FFFFFF" style="background-color:#FFFFFF;padding-top: 36px;padding-right: 43px;padding-bottom: 25px;padding-left: 43px;border-radius: 4px;">
<h3 style=" font-family: Inter;
font-size: 20px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #262424;
width: 280px">Your verification code</h3>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #6D6666;
margin-top: 12px;">Enter the code below on the share page to access the case.</p>
<p style="font-family: 'Courier New', Courier, monospace;
font-size: 32px;
font-style: normal;
font-weight: 600;
line-height: 40px;
mso-line-height-rule:exactly;
letter-spacing: 8px;
text-align: center;
color:#262424;
background-color: #F2F0F4;
padding-top: 16px;
padding-bottom: 16px;
padding-right: 16px;
padding-left: 16px;
margin-top: 16px;
margin-bottom: 16px;
border-radius: 4px;">{{code}}</p>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #6D6666;">This code expires in {{expiry}}. If you didn't request this, you can safely ignore this email.</p>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" width="100%" bgcolor="E5E5E5" style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td bgcolor="E5E5E5">
<table border="0" cellpadding="0" cellspacing="0" width="100%" class="footer-table" style="margin-top: 0;border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;" >
<tbody>
<tr>
<td class="corner-td" align="left"></td>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;display:table-row !important">
<![endif]-->
<td height="146" width="190" class="footer-td" style="margin-bottom: 12px;" valign="top" align="left">
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td>
<h4 style=" font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#6D6666;">Get in touch</h4>
<a style="text-decoration: none;color: none;" href="mailto:support@kerberos.io">
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 16px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">support@kerberos.io</p>
</a>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 16px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">9000 Ghent, BE</p>
<a style="text-decoration: none;color: none;" href="https://kerberos.io/">
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">https://kerberos.io</p>
</a>
</td>
</tr>
</tbody>
</table>
</td>
<!--[if mso | IE]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;display:table-row !important">
<![endif]-->
<td class="footer-td" style="border-radius: 4px;padding-left: 0;padding-right: 0;padding-top: 0;padding-bottom: 0; margin-bottom: 12px;" valign="top" align="left">
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr>
<td>
<h4 style=" font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 600;
line-height: 36px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color:#6D6666;">About Kerberos</h4>
<p style=" font-family: Inter;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 24px;
mso-line-height-rule:exactly;
letter-spacing: 0em;
text-align: left;
color: #A69D9D;">Welcome to the revolutionary video analytics and video management platform. Open, modular, and extensible for everyone, anywhere.</p>
<p style="margin-top: 12px;">
<a href="https://twitter.com/kerberosio" style="text-decoration: none;color: none;">
<img width="24" height="24" alt="Twitter" src="https://kerberos.io/images/email/twitter.png"/>
</a>
<a href="https://reddit.com/r/kerberos_io" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Reddit" src="https://kerberos.io/images/email/reddit.png"/>
</a>
<a href="https://www.youtube.com/channel/UCnd9q7iRNNw4W95eQwQuECA" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Youtube" src="https://kerberos.io/images/email/youtube.png"/>
</a>
<a href="https://github.com/kerberos-io" style="text-decoration: none;color: none;">
<img g width="24" height="24" alt="Github" src="https://kerberos.io/images/email/github.png"/>
</a>
</p>
</td>
</tr>
</tbody>
</table>
</td>
<td class="corner-td" align="right"></td>
</tr>
</tbody>
</table>
<table style="border-collaps:collaps; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tbody>
<tr style="height: 50px">
<td></td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</body>
</html>
@@ -1,21 +0,0 @@
Kerberos.io
------------
Verify your access
Use the code below to open the shared case
Your verification code
{{code}}
Enter this code on the share page to access the case. This code expires in {{expiry}}.
If you didn't request this, you can safely ignore this email.
Get in touch
------------
support@kerberos.io
9000 Ghent, BE
https://kerberos.io
About Kerberos
------------
Welcome to the revolutionary video analytics and video management platform. Open, modular, and extensible for everyone, anywhere.
@@ -1,5 +0,0 @@
[
{"key": "nose", "label": "Nose"},
{"key": "left_shoulder", "label": "Left shoulder"},
{"key": "right_shoulder", "label": "Right shoulder"}
]
@@ -1,24 +0,0 @@
# Create these ConfigMaps in the release namespace before deploying the chart.
# Keys contain complete contracts/catalogs; they are not merged with chart data.
# Do not also set classificationCatalog or classificationCatalogExistingConfigMap.
classificationCatalogEnabled: true
workflowConfiguration:
enabled: true
includeDefaults: true
configMaps:
- name: deployment-workflow-overrides
items:
- key: start.yaml
path: workflow-contracts/start.yaml
replace: true
- key: deployment-classifications.json
path: catalogs/classifications.json
replace: true
- name: custom-workflow-contracts
items:
- key: pose.yaml
path: workflow-contracts/pose.yaml
- name: shared-pose-catalog
items:
- key: pose-keypoints.json
path: catalogs/pose-keypoints.json
@@ -1,13 +0,0 @@
# Packaging only; does not activate contract loading or deploy a pose worker.
workflowConfiguration:
enabled: true
includeDefaults: true
configMaps:
- name: custom-workflow-contracts
items:
- key: pose.yaml
path: workflow-contracts/pose.yaml
- name: shared-pose-catalog
items:
- key: pose-keypoints.json
path: catalogs/pose-keypoints.json
@@ -1,53 +0,0 @@
# yaml-language-server: $schema=../../schemas/workflow-contract.schema.json
# Hypothetical custom worker output; not an installed stage or universal pose schema.
schemaVersion: 1
stage: pose
contractVersion: 1
presentation:
name: Detect poses
description: Estimate body keypoints and posture for people in the recording.
icon: person
color: teal
# Settings authors enter per node; the worker receives them as node data.
params:
- name: minConfidence
label: Minimum keypoint confidence
type: number
default: 0.5
- name: model
label: Model
type: select
options: [fast, accurate]
optionLabels: {fast: Fast, accurate: Accurate}
default: fast
fields:
- id: keypoint
label: Keypoint
path: people.*.keypoints.*.name
type: string
operators: [in]
choices:
file: ../catalogs/pose-keypoints.json
- id: posture
label: Posture
path: people.*.posture
type: string
operators: [in]
choices:
values: [standing, sitting, lying]
- id: confidence
label: Keypoint confidence
path: people.*.keypoints.*.confidence
type: number
operators: [gt, gte, lt, lte]
minimum: 0
maximum: 1
# Connections leaving this stage: one section with fixed inputs, then the
# Extra conditions catch-all (appended collapsed when not placed explicitly).
panel:
sections:
- id: posture
label: Posture
fields:
- {field: posture, widget: multiselect}
- {field: confidence, widget: number, operator: gte, label: Minimum confidence}
-17
View File
@@ -1,17 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Hub shared choice catalog v1",
"description": "Compatible with the existing classification JSON format. Keys must be unique; no references to other catalogs.",
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["key", "label"],
"properties": {
"key": {"type": "string", "minLength": 1},
"label": {"type": "string", "minLength": 1},
"icon": {"type": "string", "minLength": 1}
}
}
}
@@ -1,321 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Hub workflow editor contract v1",
"type": "object",
"additionalProperties": false,
"required": ["schemaVersion", "stage", "contractVersion", "fields"],
"properties": {
"schemaVersion": {"const": 1},
"stage": {
"type": "string",
"pattern": "^[a-z][a-z0-9-]*$",
"description": "Stage type, not a node instance. start describes initial context."
},
"contractVersion": {"const": 1},
"presentation": {
"type": "object",
"additionalProperties": false,
"description": "How the editor shows this node. Icons and colours come from approved sets.",
"properties": {
"name": {"type": "string", "minLength": 1, "maxLength": 80},
"description": {"type": "string", "minLength": 1, "maxLength": 500},
"icon": {"enum": ["play", "camera", "person", "eye-crossed", "car", "clock", "mlModel", "share"]},
"color": {
"enum": ["blue", "teal", "rose", "amber", "indigo", "violet", "green", "grey"],
"description": "Theme colour token."
}
}
},
"params": {
"type": "array",
"maxItems": 64,
"description": "Worker-stage settings authors enter, stored per node. An explicit list (even empty) replaces kerberoshub.workflows.editorStages params. Not supported on start.",
"items": {"$ref": "#/definitions/param"}
},
"fields": {
"type": "array",
"description": "Typed values conditions may test. Start: the selectors device, sites, groups and classifications plus condition-only fields whose path exists in the condition root schema (models.WorkflowConditionRootSchema), e.g. device.deviceName or inputs.classify.details.*.isStatic; other inputs.<operation> paths are worker-defined. Stage: outputs relative to results.<stage>. New conditions may only use declared fields. An empty array is valid.",
"items": {"$ref": "#/definitions/field"},
"maxItems": 128
},
"controls": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "label"],
"properties": {
"id": {"enum": ["weeklySchedule", "conditions"]},
"label": {"type": "string", "minLength": 1}
}
},
"description": "Start only. Controls offered for new authoring; omitted offers none. conditions applies to edges leaving Start.",
"maxItems": 16
},
"triggerModes": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {"enum": ["automatic", "manual"]},
"description": "Start only. Trigger modes offered for new authoring; omitted offers both."
},
"panel": {"$ref": "#/definitions/panel"}
},
"definitions": {
"choices": {
"type": "object",
"additionalProperties": false,
"properties": {
"source": {
"type": "string",
"description": "Built-in authorized project-resource resolver; not a database path.",
"oneOf": [
{
"const": "project.devices",
"description": "Device keys as values, device names as labels."
},
{"const": "project.sites", "description": "Site IDs as values, site names as labels."},
{
"const": "project.groups",
"description": "Group IDs as values, group names as labels."
}
]
},
"file": {
"type": "string",
"pattern": "^\\.\\./catalogs/[A-Za-z0-9_-][A-Za-z0-9._-]*\\.json$",
"description": "Direct shared catalog file relative to the contract; no URLs or nested references."
},
"values": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {"type": ["string", "number", "boolean"]}
}
},
"oneOf": [{"required": ["source"]}, {"required": ["file"]}, {"required": ["values"]}]
},
"field": {
"type": "object",
"additionalProperties": false,
"required": ["id", "label", "path", "type", "operators"],
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z][A-Za-z0-9_-]*$",
"description": "Stable identifier, unique within this contract."
},
"label": {"type": "string", "minLength": 1},
"path": {
"type": "string",
"pattern": "^[A-Za-z_][A-Za-z0-9_-]*(\\.(\\*|[A-Za-z_][A-Za-z0-9_-]*))*$",
"description": "Safe Start-context path, or relative path inside this node instance's output. Wildcards select scalar candidates."
},
"type": {"enum": ["string", "integer", "number", "boolean"]},
"operators": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {"enum": ["eq", "ne", "in", "exists", "contains", "matches", "gt", "gte", "lt", "lte"]}
},
"optional": {
"type": "boolean",
"default": false,
"description": "Field may be absent even when the node completes; branch availability is determined separately."
},
"minimum": {"type": "number"},
"maximum": {"type": "number"},
"choices": {"$ref": "#/definitions/choices"}
},
"allOf": [
{
"if": {"properties": {"type": {"const": "string"}}},
"then": {
"properties": {
"operators": {"items": {"enum": ["eq", "ne", "in", "exists", "contains", "matches"]}},
"choices": {"properties": {"values": {"items": {"type": "string"}}}}
},
"not": {"anyOf": [{"required": ["minimum"]}, {"required": ["maximum"]}]}
}
},
{
"if": {"properties": {"type": {"const": "boolean"}}},
"then": {
"properties": {
"operators": {"items": {"enum": ["eq", "ne", "in", "exists"]}},
"choices": {"properties": {"values": {"items": {"type": "boolean"}}}}
},
"not": {"anyOf": [{"required": ["minimum"]}, {"required": ["maximum"]}]}
}
},
{
"if": {"properties": {"type": {"enum": ["integer", "number"]}}},
"then": {
"properties": {
"operators": {"items": {"enum": ["eq", "ne", "in", "exists", "gt", "gte", "lt", "lte"]}},
"choices": {"properties": {"values": {"items": {"type": "number"}}}}
}
}
},
{
"if": {"properties": {"type": {"const": "integer"}}},
"then": {"properties": {"choices": {"properties": {"values": {"items": {"type": "integer"}}}}}}
},
{
"if": {"properties": {"type": {"enum": ["integer", "number", "boolean"]}}},
"then": {
"properties": {"choices": {"not": {"anyOf": [{"required": ["file"]}, {"required": ["source"]}]}}}
}
}
]
},
"param": {
"type": "object",
"additionalProperties": false,
"required": ["name", "type"],
"properties": {
"name": {
"type": "string",
"pattern": "^[A-Za-z][A-Za-z0-9_]*$",
"maxLength": 64,
"description": "Key in node data; unique within the contract."
},
"label": {"type": "string", "minLength": 1, "maxLength": 160},
"description": {"type": "string", "minLength": 1, "maxLength": 500},
"group": {
"type": "string",
"minLength": 1,
"maxLength": 80,
"description": "Editor section; params sharing a group appear together."
},
"placeholder": {"type": "string", "minLength": 1, "maxLength": 160},
"type": {"enum": ["string", "number", "boolean", "select", "multiselect", "secret"]},
"required": {"type": "boolean"},
"default": {
"description": "Value the editor pre-fills and the API stores when a node leaves the setting unset; never for secrets. Typically the worker's own default."
},
"options": {
"type": "array",
"minItems": 1,
"maxItems": 256,
"uniqueItems": true,
"items": {"type": "string", "minLength": 1, "maxLength": 160}
},
"optionLabels": {
"type": "object",
"additionalProperties": {"type": "string", "minLength": 1, "maxLength": 160}
},
"minimum": {"type": "number", "description": "Inclusive lower bound for a number setting."},
"maximum": {"type": "number", "description": "Inclusive upper bound for a number setting."},
"choices": {
"type": "object",
"additionalProperties": false,
"required": ["file"],
"properties": {
"file": {"type": "string", "pattern": "^\\.\\./catalogs/[A-Za-z0-9_-][A-Za-z0-9._-]*\\.json$"}
},
"description": "Options for a select or multiselect setting from a shared catalog file (keys become options, labels become optionLabels). Use instead of options."
}
},
"allOf": [
{
"if": {"properties": {"type": {"enum": ["select", "multiselect"]}}},
"then": {"oneOf": [{"required": ["options"]}, {"required": ["choices"]}]},
"else": {
"not": {
"anyOf": [{"required": ["options"]}, {"required": ["optionLabels"]}, {"required": ["choices"]}]
}
}
},
{
"if": {"properties": {"type": {"const": "secret"}}},
"then": {"not": {"required": ["default"]}}
},
{
"if": {"properties": {"type": {"enum": ["string", "select"]}}},
"then": {"properties": {"default": {"type": "string"}}}
},
{
"if": {"properties": {"type": {"const": "multiselect"}}},
"then": {
"properties": {"default": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}}
}
},
{
"if": {"properties": {"type": {"const": "number"}}},
"then": {"properties": {"default": {"type": "number"}}},
"else": {"not": {"anyOf": [{"required": ["minimum"]}, {"required": ["maximum"]}]}}
},
{
"if": {"properties": {"type": {"const": "boolean"}}},
"then": {"properties": {"default": {"type": "boolean"}}}
}
]
},
"panel": {
"type": "object",
"additionalProperties": false,
"required": ["sections"],
"description": "Layout of connections leaving this node. Without it, a default panel is used. A section with picker: true positions the Extra conditions catch-all; without one it is appended collapsed. On start, a panel replaces the top-level controls list.",
"properties": {
"sections": {
"type": "array",
"minItems": 1,
"maxItems": 16,
"items": {"$ref": "#/definitions/panelSection"}
}
}
},
"panelSection": {
"type": "object",
"additionalProperties": false,
"required": ["id", "label"],
"properties": {
"id": {"type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]*$", "maxLength": 80},
"label": {"type": "string", "minLength": 1, "maxLength": 160},
"collapsed": {"type": "boolean"},
"picker": {
"type": "boolean",
"description": "This section is the Extra conditions catch-all over every declared field of Start and upstream stages; it holds no fields or controls."
},
"controls": {
"type": "array",
"items": {"const": "weeklySchedule"},
"maxItems": 1,
"description": "Start only."
},
"fields": {"type": "array", "maxItems": 32, "items": {"$ref": "#/definitions/panelField"}}
},
"if": {"properties": {"picker": {"const": true}}, "required": ["picker"]},
"then": {"not": {"anyOf": [{"required": ["fields"]}, {"required": ["controls"]}]}}
},
"panelField": {
"type": "object",
"additionalProperties": false,
"required": ["field", "widget"],
"properties": {
"field": {
"type": "string",
"description": "ID of a field declared in this contract; each field is placed at most once."
},
"label": {"type": "string", "minLength": 1, "maxLength": 160},
"widget": {
"enum": ["multiselect", "select", "text", "number", "toggle"],
"description": "multiselect: string with choices (in); select: choices (eq, ne); text: string (eq, contains, matches, ne, in); number: integer or number (gte, gt, lte, lt, eq, ne); toggle: boolean (eq, ne)."
},
"operator": {
"enum": ["eq", "ne", "in", "contains", "matches", "gt", "gte", "lt", "lte"],
"description": "Fixed operator; must be declared by the field and supported by the widget. Defaults to the first widget operator the field declares."
}
}
}
},
"allOf": [
{
"if": {"properties": {"stage": {"const": "start"}}, "required": ["stage"]},
"then": {"not": {"required": ["params"]}},
"else": {"not": {"anyOf": [{"required": ["controls"]}, {"required": ["triggerModes"]}]}}
},
{"if": {"required": ["panel"]}, "then": {"not": {"required": ["controls"]}}}
]
}
-128
View File
@@ -1,128 +0,0 @@
{{- define "hub.workflowConfiguration.bundledPaths" -}}
{{- list "workflow-contracts/start.yaml" "workflow-contracts/anpr.yaml" "workflow-contracts/forwarder.yaml" "catalogs/classifications.json" | toYaml -}}
{{- end -}}
{{- define "hub.workflowConfiguration.anpr.configMapName" -}}
{{- printf "%s-workflow-contract-anpr" (.Release.Name | trunc 40 | trimSuffix "-") -}}
{{- end -}}
{{- define "hub.workflowConfiguration.forwarder.configMapName" -}}
{{- printf "%s-workflow-contract-forwarder" (.Release.Name | trunc 40 | trimSuffix "-") -}}
{{- end -}}
{{- define "hub.classificationCatalog.configMapName" -}}
{{- $config := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- $replacement := index $config.replacements "catalogs/classifications.json" | default dict -}}
{{- if $replacement -}}
{{- $replacement.name -}}
{{- else -}}
{{- default "classification-catalog" .Values.classificationCatalogExistingConfigMap -}}
{{- end -}}
{{- end -}}
{{/* Normalize both interfaces without changing the caller's values. */}}
{{- define "hub.workflowConfiguration.settings" -}}
{{- $config := .Values.workflowConfiguration | default dict -}}
{{- $unified := or (hasKey $config "includeDefaults") (hasKey $config "configMaps") -}}
{{- $legacy := or (hasKey $config "existingConfigMap") (hasKey $config "items") (hasKey $config "extraConfigMaps") -}}
{{- if and $unified $legacy -}}
{{- fail "workflowConfiguration cannot mix includeDefaults/configMaps with existingConfigMap/items/extraConfigMaps" -}}
{{- end -}}
{{- $includeDefaults := true -}}
{{- $sources := $config.extraConfigMaps | default list -}}
{{- if $unified -}}
{{- $sources = $config.configMaps | default list -}}
{{- if hasKey $config "includeDefaults" -}}
{{- $includeDefaults = $config.includeDefaults -}}
{{- end -}}
{{- else -}}
{{- if $config.existingConfigMap -}}
{{- if and $config.enabled (not $config.items) -}}
{{- fail "workflowConfiguration.items is required with existingConfigMap" -}}
{{- end -}}
{{- $includeDefaults = false -}}
{{- $sources = prepend $sources (dict "name" $config.existingConfigMap "items" ($config.items | default list)) -}}
{{- else if and $config.enabled $config.items -}}
{{- fail "workflowConfiguration.items requires existingConfigMap" -}}
{{- end -}}
{{- end -}}
{{- $enabled := $config.enabled | default false -}}
{{- $replacements := dict -}}
{{- $normalizedSources := list -}}
{{- $bundledPaths := include "hub.workflowConfiguration.bundledPaths" . | fromYamlArray -}}
{{- range $sources -}}
{{- $name := .name -}}
{{- $items := list -}}
{{- range .items -}}
{{- if and $enabled .replace -}}
{{- if or (not $unified) (not $includeDefaults) -}}
{{- fail "workflowConfiguration item replace: true requires configMaps with includeDefaults: true" -}}
{{- end -}}
{{- if not (has .path $bundledPaths) -}}
{{- fail (printf "workflowConfiguration item replace: true targets unknown bundled path %q" .path) -}}
{{- end -}}
{{- if hasKey $replacements .path -}}
{{- fail (printf "duplicate workflowConfiguration replacement path %q" .path) -}}
{{- end -}}
{{- $_ := set $replacements .path (dict "name" $name "key" .key) -}}
{{- end -}}
{{- $items = append $items (omit . "replace") -}}
{{- end -}}
{{- $normalizedSources = append $normalizedSources (dict "name" $name "items" $items) -}}
{{- end -}}
{{- if hasKey $replacements "catalogs/classifications.json" -}}
{{- if .Values.classificationCatalogExistingConfigMap -}}
{{- fail "a classifications.json replacement cannot be combined with classificationCatalogExistingConfigMap; choose one override mechanism" -}}
{{- end -}}
{{- end -}}
{{- if not (kindIs "invalid" .Values.classificationCatalog) -}}
{{- if not .Values.classificationCatalogEnabled -}}
{{- fail "classificationCatalog requires classificationCatalogEnabled; remove the inline list to use the API fallback" -}}
{{- end -}}
{{- if .Values.classificationCatalogExistingConfigMap -}}
{{- fail "classificationCatalog cannot be combined with classificationCatalogExistingConfigMap; choose one override mechanism" -}}
{{- end -}}
{{- if hasKey $replacements "catalogs/classifications.json" -}}
{{- fail "classificationCatalog cannot be combined with a classifications.json replacement; choose one override mechanism" -}}
{{- end -}}
{{- end -}}
{{- dict "enabled" $enabled "includeDefaults" $includeDefaults "configMaps" $normalizedSources "replacements" $replacements | toYaml -}}
{{- end -}}
{{- define "hub.workflowConfiguration.validate" -}}
{{- $config := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- if $config.enabled -}}
{{- $paths := dict -}}
{{- if $config.includeDefaults -}}
{{- if not .Values.classificationCatalogEnabled -}}
{{- fail "bundled workflowConfiguration requires classificationCatalogEnabled; disable includeDefaults and supply configMaps for a custom bundle" -}}
{{- end -}}
{{- range $path := (include "hub.workflowConfiguration.bundledPaths" . | fromYamlArray) -}}
{{- if not (hasKey $config.replacements $path) -}}
{{- $_ := set $paths $path true -}}
{{- end -}}
{{- end -}}
{{- else -}}
{{- if not $config.configMaps -}}
{{- fail "workflowConfiguration.configMaps must be nonempty when enabled without defaults" -}}
{{- end -}}
{{- end -}}
{{- range $config.configMaps -}}
{{- if not .items -}}
{{- fail (printf "workflowConfiguration ConfigMap %q requires nonempty items" .name) -}}
{{- end -}}
{{- range .items -}}
{{- if not (regexMatch "^[A-Za-z0-9._-]+$" .key) -}}
{{- fail "workflowConfiguration.items keys must be valid ConfigMap keys" -}}
{{- end -}}
{{- if or (not (regexMatch "^(workflow-contracts|catalogs)/[A-Za-z0-9_-][A-Za-z0-9._-]*\\.(yaml|json)$" .path)) (ne (clean .path) .path) -}}
{{- fail "workflowConfiguration.items paths must be normalized relative files under workflow-contracts/ or catalogs/" -}}
{{- end -}}
{{- if hasKey $paths .path -}}
{{- fail (printf "duplicate workflowConfiguration.items path %q" .path) -}}
{{- end -}}
{{- $_ := set $paths .path true -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
-51
View File
@@ -1,51 +0,0 @@
{{/*
The system tag catalog (deviceTags.system.catalog) uses the Hub shared choice
catalog format: {key, label, description?}. values.schema.json validates each
entry (key in stored device tag form, models.NormalizeDeviceTags: 1-64
characters of a-z, 0-9, ".", "_", ":" and "-", starting and ending with a
letter or digit) and that enabled is a boolean; keys must also be unique.
*/}}
{{- define "kerberoshub.deviceTags.system.validate" -}}
{{- $seen := dict -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $key := toString $tag.key -}}
{{- if hasKey $seen $key -}}
{{- fail (printf "deviceTags.system.catalog: duplicate key %q" $key) -}}
{{- end -}}
{{- $_ := set $seen $key true -}}
{{- end -}}
{{- end -}}
{{/*
The configured system tag catalog as a JSON array, whether or not system tags
are enabled (missing values read as empty).
*/}}
{{- define "kerberoshub.deviceTags.system.catalog" -}}
{{- $deviceTags := .Values.deviceTags | default dict -}}
{{- $system := $deviceTags.system | default dict -}}
{{- $system.catalog | default list | toJson -}}
{{- end -}}
{{/*
Whether system tags are enabled (deviceTags.system.enabled): "true" or "".
*/}}
{{- define "kerberoshub.deviceTags.system.enabled" -}}
{{- $deviceTags := .Values.deviceTags | default dict -}}
{{- $system := $deviceTags.system | default dict -}}
{{- if and (kindIs "bool" $system.enabled) $system.enabled -}}true{{- end -}}
{{- end -}}
{{/*
The system tag catalog file hub-api reads (DEVICE_SYSTEM_TAGS_FILE), rendered
from deviceTags.system.catalog into the device-system-tags ConfigMap.
*/}}
{{- define "kerberoshub.deviceTags.system.json" -}}
{{- include "kerberoshub.deviceTags.system.validate" . -}}
{{- $tags := list -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $entry := dict "key" $tag.key "label" $tag.label -}}
{{- with $tag.description }}{{- $_ := set $entry "description" . -}}{{- end }}
{{- $tags = append $tags $entry -}}
{{- end -}}
{{- $tags | toJson -}}
{{- end -}}
-108
View File
@@ -1,108 +0,0 @@
{{/* Build the path to the configured MongoDB CA bundle. */}}
{{- define "hub.mongodb.tlsCAFile" -}}
{{- if and .Values.mongodb.tls.enabled .Values.mongodb.tls.existingSecret .Values.mongodb.tls.caFileName -}}
{{- printf "%s/%s" .Values.mongodb.tls.mountPath .Values.mongodb.tls.caFileName | clean -}}
{{- end -}}
{{- end -}}
{{/* Add TLS options to a configured MongoDB URI unless they are already present. */}}
{{- define "hub.mongodb.uri" -}}
{{- $uri := .Values.mongodb.uri | default "" -}}
{{- if and .Values.mongodb.tls.enabled $uri -}}
{{- if not (regexMatch "(?i)(^|[?&])tls=" $uri) -}}
{{- $separator := "?" -}}
{{- if contains "?" $uri -}}
{{- $separator = "&" -}}
{{- end -}}
{{- if or (hasSuffix "?" $uri) (hasSuffix "&" $uri) -}}
{{- $separator = "" -}}
{{- end -}}
{{- $uri = printf "%s%stls=true" $uri $separator -}}
{{- end -}}
{{- $caFile := include "hub.mongodb.tlsCAFile" . -}}
{{- if and $caFile (not (regexMatch "(?i)(^|[?&])tlsCAFile=" $uri)) -}}
{{- $separator := "&" -}}
{{- if not (contains "?" $uri) -}}
{{- $separator = "?" -}}
{{- else if or (hasSuffix "?" $uri) (hasSuffix "&" $uri) -}}
{{- $separator = "" -}}
{{- end -}}
{{- $uri = printf "%s%stlsCAFile=%s" $uri $separator $caFile -}}
{{- end -}}
{{- end -}}
{{- $uri -}}
{{- end -}}
{{/*
MongoDB URI with appName set to one workload, so the Atlas query profiler and
currentOp attribute each operation to the service that issued it. Renders
nothing when no URI is configured or mongodb.appNamePerService is false.
Usage: include "hub.mongodb.appUri" (dict "root" $ "app" "hub-api")
*/}}
{{- define "hub.mongodb.appUri" -}}
{{- $uri := include "hub.mongodb.uri" .root -}}
{{- if and $uri .root.Values.mongodb.appNamePerService -}}
{{- if regexMatch "(?i)[?&]appName=" $uri -}}
{{- $uri = regexReplaceAll "(?i)([?&])appName=[^&]*" $uri (printf "${1}appName=%s" .app) -}}
{{- else -}}
{{- $separator := "&" -}}
{{- if not (contains "?" $uri) -}}
{{- $separator = "?" -}}
{{- else if or (hasSuffix "?" $uri) (hasSuffix "&" $uri) -}}
{{- $separator = "" -}}
{{- end -}}
{{- $uri = printf "%s%sappName=%s" $uri $separator .app -}}
{{- end -}}
{{- $uri -}}
{{- end -}}
{{- end -}}
{{/*
Container env entry that overrides MONGODB_URI from mongodb-config with the
workload's own appName. An explicit env entry takes precedence over envFrom.
Usage: {{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-api") | nindent 12 }}
*/}}
{{- define "hub.mongodb.appUriEnv" -}}
{{- with include "hub.mongodb.appUri" . -}}
- name: MONGODB_URI
value: {{ . | quote }}
{{- end -}}
{{- end -}}
{{/* Render the shared MongoDB CA Secret volume. */}}
{{- define "hub.mongodb.tlsVolume" -}}
- name: mongodb-tls
secret:
secretName: {{ .Values.mongodb.tls.existingSecret }}
{{- end -}}
{{/* Render the shared MongoDB CA volume mount. */}}
{{- define "hub.mongodb.tlsVolumeMount" -}}
- name: mongodb-tls
mountPath: {{ .Values.mongodb.tls.mountPath }}
readOnly: true
{{- end -}}
{{/*
OpenTelemetry sampling env.
"hub.opentelemetry.samplerEnv" is for the services that only continue traces
started elsewhere (hub-workflows, pipe-*, workflow stages): they follow the
parent's sampling decision and never start traces of their own.
"hub.opentelemetry.apiSamplerEnv" renders hub-api's per-class sampling ratios
(opentelemetry.apiSamplingRatios) as TRACE_SAMPLER_RATIO_<CLASS>; empty values
are not rendered.
Usage: {{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
*/}}
{{- define "hub.opentelemetry.samplerEnv" -}}
- name: OTEL_TRACES_SAMPLER
value: "parentbased_always_off"
{{- end -}}
{{- define "hub.opentelemetry.apiSamplerEnv" -}}
{{- range $class, $ratio := (.Values.opentelemetry.apiSamplingRatios | default dict) }}
{{- if ne (toString $ratio) "" }}
- name: TRACE_SAMPLER_RATIO_{{ upper $class }}
value: {{ toString $ratio | quote }}
{{- end }}
{{- end }}
{{- end -}}
+1 -13
View File
@@ -26,10 +26,6 @@ spec:
- name: admin
image: "{{ .Values.global.imageRegistry }}{{ .Values.admin.repository }}:{{ .Values.admin.tag }}"
imagePullPolicy: {{ .Values.admin.pullPolicy }}
{{- with .Values.admin.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.admin.resources }}
resources:
{{- toYaml . | nindent 12 }}
@@ -40,16 +36,8 @@ spec:
{{- end }}
ports:
- name: http
containerPort: {{ .Values.admin.containerPort | default 80 }}
containerPort: 80
protocol: TCP
{{- with .Values.admin.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.admin.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
- name: LOG_LEVEL
value: "{{ .Values.admin.logLevel }}"
+1 -1
View File
@@ -10,7 +10,7 @@ spec:
ports:
- protocol: TCP
port: 80
targetPort: http
targetPort: 80
name: http
selector:
app: admin
@@ -1,46 +0,0 @@
{{- define "hub.classificationCatalog.defaults" -}}
[
{"key": "animal", "label": "Animal", "icon": "animal"},
{"key": "pedestrian", "label": "Pedestrian", "icon": "pedestrian"},
{"key": "cyclist", "label": "Cyclist", "icon": "cyclist"},
{"key": "motorbike", "label": "Motorbike", "icon": "motorbike"},
{"key": "lorry", "label": "Lorry", "icon": "lorry"},
{"key": "car", "label": "Car", "icon": "car"},
{"key": "handbag", "label": "Handbag", "icon": "handbag"},
{"key": "suitcase", "label": "Suitcase", "icon": "suitcase"},
{"key": "cell phone", "label": "Cell phone", "icon": "cell phone"}
]
{{- end -}}
{{/*
The effective chart-rendered catalog: the inline classificationCatalog values
list when set, otherwise the bundled defaults above. values.schema.json
validates each entry ({key, label, icon?}); keys must also be unique.
*/}}
{{- define "hub.classificationCatalog.json" -}}
{{- if kindIs "invalid" .Values.classificationCatalog -}}
{{- include "hub.classificationCatalog.defaults" . | mustFromJson | toJson -}}
{{- else if and (kindIs "slice" .Values.classificationCatalog) .Values.classificationCatalog -}}
{{- $seen := dict -}}
{{- range $entry := .Values.classificationCatalog -}}
{{- $key := toString $entry.key -}}
{{- if hasKey $seen $key -}}
{{- fail (printf "classificationCatalog: duplicate key %q" $key) -}}
{{- end -}}
{{- $_ := set $seen $key true -}}
{{- end -}}
{{- .Values.classificationCatalog | toJson -}}
{{- else -}}
{{- fail "classificationCatalog must be omitted (bundled defaults) or a nonempty list; to use the API fallback set classificationCatalogEnabled: false" -}}
{{- end -}}
{{- end -}}
{{- $config := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- if and .Values.classificationCatalogEnabled (not .Values.classificationCatalogExistingConfigMap) (not (hasKey $config.replacements "catalogs/classifications.json")) }}
apiVersion: v1
kind: ConfigMap
metadata:
name: classification-catalog
namespace: {{ .Release.Namespace }}
data:
classifications.json: |-
{{- include "hub.classificationCatalog.json" . | mustFromJson | toPrettyJson | nindent 4 }}
{{- end -}}
@@ -1,12 +0,0 @@
{{- if include "kerberoshub.deviceTags.system.enabled" . }}
apiVersion: v1
kind: ConfigMap
metadata:
name: device-system-tags
namespace: {{ .Release.Namespace }}
data:
# Rendered from deviceTags.system.catalog; hub-api reads it through
# DEVICE_SYSTEM_TAGS_FILE.
system-tags.json: |-
{{- include "kerberoshub.deviceTags.system.json" . | mustFromJson | toPrettyJson | nindent 4 }}
{{- end -}}
@@ -1,51 +0,0 @@
{{- if .Values.audit.enabled -}}
{{- $destinations := list -}}
{{- $destinationIDs := dict -}}
{{- range $index, $destination := .Values.kerberoshub.audit.destinations -}}
{{- $id := required (printf "id is required for audit destination %d" $index) $destination.id -}}
{{- if not (regexMatch "^[a-z][a-z0-9-]{0,62}$" $id) -}}
{{- fail (printf "audit destination id %q must match ^[a-z][a-z0-9-]{0,62}$" $id) -}}
{{- end -}}
{{- if hasKey $destinationIDs $id -}}
{{- fail (printf "duplicate audit destination id %q" $id) -}}
{{- end -}}
{{- $_ := set $destinationIDs $id true -}}
{{- $url := required (printf "url is required for audit destination %s" $id) $destination.url -}}
{{- $entry := dict
"id" $id
"type" (default "webhook" $destination.type)
"enabled" $destination.enabled
"url" $url
"timeoutSeconds" (default 10 $destination.timeoutSeconds)
"batchSize" (default 100 $destination.batchSize)
"maxAttempts" (default 10 $destination.maxAttempts)
"startAt" (default "latest" $destination.startAt)
"headers" (default dict $destination.headers)
"filters" (default dict $destination.filters) -}}
{{- $secretRoot := printf "/var/run/secrets/audit-destinations/%s" $id -}}
{{- $bearer := default dict $destination.bearerTokenSecret -}}
{{- if gt (len $bearer) 0 -}}
{{- $secretName := required (printf "bearerTokenSecret.name is required for destination %s" $id) $bearer.name -}}
{{- $secretKey := default "token" $bearer.key -}}
{{- $_ := set $entry "bearerTokenFile" (printf "%s/bearer-%s" $secretRoot (sha256sum (printf "%s:%s" $secretName $secretKey) | trunc 12)) -}}
{{- end -}}
{{- $headerFiles := dict -}}
{{- range $headerName, $secret := (default dict $destination.secretHeaders) -}}
{{- $secretName := required (printf "secretName is required for destination %s header %s" $id $headerName) $secret.secretName -}}
{{- $secretKey := required (printf "secretKey is required for destination %s header %s" $id $headerName) $secret.secretKey -}}
{{- $_ := set $headerFiles $headerName (printf "%s/header-%s" $secretRoot (sha256sum (printf "%s:%s:%s" $headerName $secretName $secretKey) | trunc 12)) -}}
{{- end -}}
{{- if gt (len $headerFiles) 0 -}}
{{- $_ := set $entry "headerFiles" $headerFiles -}}
{{- end -}}
{{- $destinations = append $destinations $entry -}}
{{- end -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: hub-audit
namespace: {{ .Release.Namespace }}
data:
destinations.json: |
{{ dict "version" 1 "destinations" $destinations | toPrettyJson | nindent 4 }}
{{- end }}
@@ -1,135 +0,0 @@
{{/* Validate the rendered anpr.yaml payload against schemas/workflow-contract.schema.json in the chart root. */}}
{{- define "hub.workflowConfiguration.anpr" -}}
schemaVersion: 1
stage: anpr
contractVersion: 1
presentation:
name: Number plate recognition
description: Read the number plates of vehicles in the recording.
icon: car
color: amber
# Node settings hub-anpr reads per run (see its README, "Node settings"). Each
# overrides the matching ANPR_* environment variable; the defaults below equal
# the worker's built-in defaults. A deployment that changes those variables
# should change these defaults too, because new nodes store them on save.
params:
- name: plateClasses
label: Read plates for
description: Vehicle classes whose plates are read (ANPR_PLATE_CLASSES).
type: multiselect
choices: {file: ../catalogs/classifications.json}
default: [car]
group: Which vehicles
- name: minMovement
label: Minimum movement
description: Skip vehicles that barely moved; 0 reads every vehicle (ANPR_READ_MOVEMENT_MIN).
type: number
minimum: 0
default: 0
group: Which vehicles
- name: maxJump
label: Maximum jump between frames
description: Drop unstable tracks; 0 disables the check (ANPR_READ_MAX_JUMP).
type: number
minimum: 0
default: 0
group: Which vehicles
- name: readFrames
label: Frames to read per vehicle
description: Frames OCR'd per vehicle; 0 disables OCR (ANPR_READ_FRAMES).
type: number
minimum: 0
maximum: 10
default: 1
group: Recognition
- name: readQuorum
label: Agreeing reads required
description: Reads that must agree before a plate is accepted; 0 accepts any read (ANPR_READ_QUORUM).
type: number
minimum: 0
maximum: 10
default: 0
group: Recognition
- name: minConfidence
label: Minimum OCR confidence
description: Ignore reads below this confidence (ANPR_READ_CONF_MIN).
type: number
minimum: 0
maximum: 1
default: 0
group: Recognition
# Paths are relative to results.anpr (models.WorkflowAnprResult): one track and
# one marker per vehicle. Plate, unread and class can be tied to the same
# vehicle with "Must match the same item"; OCR confidence and engine live on
# the markers and cannot be tied to a plate.
fields:
- id: plate
label: Number plate
path: detections.*.tracks.*.meta.plate
type: string
operators: [eq, in, contains, matches] # stored uppercase, letters and digits only, e.g. AB123CD
optional: true
- id: unread
label: Plate could not be read
path: detections.*.tracks.*.meta.unread
type: boolean
operators: [eq]
optional: true
- id: vehicleClass
label: Vehicle class (from classification)
path: detections.*.tracks.*.meta.classifiedAs
type: string
operators: [eq, in]
optional: true
choices: {file: ../catalogs/classifications.json}
- id: ocrConfidence
label: OCR confidence
path: markers.*.metadata.confidence
type: number
operators: [gte, gt, lte, lt] # read plates only; about 0-1 for fast, 0.5 for tesseract
minimum: 0
optional: true
- id: ocrEngine
label: OCR engine
path: markers.*.metadata.engine
type: string
operators: [eq, in] # read plates only
optional: true
choices: {values: [fast, tesseract, tesseract+opencv, http]}
- id: secondsVisible
label: Seconds visible
path: markers.*.duration
type: integer
operators: [gte, lte]
minimum: 0
optional: true
# Connections leaving this stage; Extra conditions are appended collapsed.
panel:
sections:
- id: plate
label: Plate
fields:
- {field: plate, widget: text, operator: contains, label: Plate contains (e.g. AB123)}
- {field: unread, widget: toggle, label: Plate could not be read}
- id: recognition
label: Recognition
collapsed: true
fields:
- {field: ocrConfidence, widget: number, operator: gte, label: Minimum OCR confidence}
- {field: vehicleClass, widget: multiselect}
- {field: secondsVisible, widget: number, operator: gte, label: Visible for at least (seconds)}
{{ end -}}
{{- $config := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- if and $config.enabled $config.includeDefaults (not (hasKey $config.replacements "workflow-contracts/anpr.yaml")) (or (eq .Values.mode "all") (eq .Values.mode "ui")) }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "hub.workflowConfiguration.anpr.configMapName" . }}
namespace: {{ .Release.Namespace }}
data:
anpr.yaml: |-
{{- include "hub.workflowConfiguration.anpr" . | nindent 4 }}
{{- end }}
@@ -1,95 +0,0 @@
{{/* Validate the rendered forwarder.yaml payload against schemas/workflow-contract.schema.json in the chart root. */}}
{{- define "hub.workflowConfiguration.forwarder" -}}
schemaVersion: 1
stage: forwarder
contractVersion: 1
presentation:
name: Forward to my system
description: Send the run's data to your own RabbitMQ destination.
icon: share
color: green
# Custom workflows supply their own connection; deployment credentials are never
# inherited. These non-secret defaults are stored on save, not read from the worker.
params:
- name: broker
label: Provider
description: Custom workflows use their own RabbitMQ destination. Shared deployment integrations are reserved for global workflows.
type: select
required: true
options: [rabbitmq]
optionLabels: {rabbitmq: RabbitMQ}
default: rabbitmq
group: Delivery
- name: mode
label: Completion mode
description: Complete after delivery, or wait for the external result. Callback requires a deployment-configured Hub callback URL.
type: select
required: true
options: [delivered, callback]
optionLabels: {delivered: Complete after delivery, callback: Wait for result}
default: delivered
group: Delivery
- name: host
label: Host
description: Your RabbitMQ destination host. Required before enabling the workflow.
type: string
required: true
placeholder: rabbitmq.example.com
group: RabbitMQ destination
- name: port
label: Port
description: Your RabbitMQ destination port, a whole number (usually 5671 with TLS or 5672 without TLS).
type: number
required: true
minimum: 1
maximum: 65535
group: RabbitMQ destination
- name: queue
label: Queue
description: Your destination queue. Its dead-letter queue is this name followed by .forwarder-dead-letter.
type: string
required: true
group: RabbitMQ destination
- name: vhost
label: Virtual host
description: Your RabbitMQ virtual host. Use / for the broker's default virtual host.
type: string
required: true
placeholder: /
group: RabbitMQ destination
- name: tls
label: Use TLS
description: Encrypt the connection and verify the broker certificate using system trust roots. Deployment TLS overrides are never inherited.
type: boolean
required: true
default: true
group: RabbitMQ destination
- name: username
label: Username
description: Your RabbitMQ destination username. Deployment credentials are never used.
type: string
required: true
group: RabbitMQ credentials
- name: password
label: Password
description: Your RabbitMQ destination password. Required before enabling the workflow; masked after saving.
type: secret
required: true
group: RabbitMQ credentials
# It contributes no output fields: connections after it can still use Start and
# earlier stages in Extra conditions.
fields: []
{{ end -}}
{{- $config := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- if and $config.enabled $config.includeDefaults (not (hasKey $config.replacements "workflow-contracts/forwarder.yaml")) (or (eq .Values.mode "all") (eq .Values.mode "ui")) }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "hub.workflowConfiguration.forwarder.configMapName" . }}
namespace: {{ .Release.Namespace }}
data:
forwarder.yaml: |-
{{- include "hub.workflowConfiguration.forwarder" . | nindent 4 }}
{{- end }}
@@ -1,75 +0,0 @@
{{/* Validate the rendered start.yaml payload against schemas/workflow-contract.schema.json in the chart root. */}}
{{- define "hub.workflowConfiguration.start" -}}
schemaVersion: 1
stage: start
contractVersion: 1
# Paths refer to the safe initial context, not the full event or credentials.
fields:
- id: device
label: Device
path: device.deviceKey
type: string
operators: [eq, in]
choices:
source: project.devices
- id: sites
label: Sites
path: device.siteIds.*
type: string
operators: [in]
choices:
source: project.sites
- id: groups
label: Groups
path: device.groupIds.*
type: string
operators: [in]
choices:
source: project.groups
- id: classifications
label: Initial classifications
path: inputs.classify.details.*.classified
type: string
operators: [in]
optional: true
choices:
file: ../catalogs/classifications.json
# Condition-only context fields (not selectors): advanced conditions on
# Start connections may test only declared fields, under device. or inputs.
- id: deviceName
label: Camera name
path: device.deviceName
type: string
operators: [eq, in, contains, matches]
- id: objectClass
label: Detected object
path: inputs.classify.details.*.classified
type: string
operators: [eq, ne, in, exists]
optional: true
choices:
file: ../catalogs/classifications.json
# Controls offered for new authoring; an omitted control is not offered.
controls:
- id: weeklySchedule
label: Weekly schedule
- id: conditions
label: Advanced conditions
# Trigger modes offered for new authoring; omitted offers both.
triggerModes: [automatic, manual]
{{ end -}}
{{- include "hub.workflowConfiguration.validate" . -}}
{{- $config := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- if and $config.enabled $config.includeDefaults (not (hasKey $config.replacements "workflow-contracts/start.yaml")) (or (eq .Values.mode "all") (eq .Values.mode "ui")) }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ printf "%s-workflow-configuration" .Release.Name | trunc 63 | trimSuffix "-" }}
namespace: {{ .Release.Namespace }}
data:
start.yaml: |-
{{- include "hub.workflowConfiguration.start" . | nindent 4 }}
{{- end }}
@@ -4,7 +4,7 @@ metadata:
name: mongodb-config
namespace: {{ .Release.Namespace }}
data:
MONGODB_URI: {{ include "hub.mongodb.uri" . | quote }}
MONGODB_URI: "{{ .Values.mongodb.uri }}"
MONGODB_HOST: "{{ .Values.mongodb.host }}"
MONGODB_AUTHENTICATION_MECHANISM: "{{ .Values.mongodb.authenticationMechanism }}"
MONGODB_DATABASE_CREDENTIALS: "{{ .Values.mongodb.adminDatabase }}"
@@ -12,7 +12,4 @@ data:
MONGODB_PASSWORD: "{{ .Values.mongodb.password }}"
MONGODB_RETRY_WRITES: "{{ .Values.mongodb.retryWrites }}"
MONGODB_FLAVOR: "{{ .Values.mongodb.flavor | default "mongodb" }}"
MONGODB_TLS: "{{ .Values.mongodb.tls.enabled }}"
MONGODB_TLS_CA_FILE: {{ include "hub.mongodb.tlsCAFile" . | quote }}
MONGODB_TLS_INSECURE_SKIP_VERIFY: "{{ .Values.mongodb.tls.insecureSkipVerify }}"
MONGODB_DATABASE_CLOUD: "Kerberos"
+6 -199
View File
@@ -1,6 +1,4 @@
{{- if or (eq .Values.mode "all") (eq .Values.mode "ui") -}}
{{- $workflowConfiguration := include "hub.workflowConfiguration.settings" . | fromYaml -}}
{{- $catalogReplacement := index $workflowConfiguration.replacements "catalogs/classifications.json" | default dict -}}
{{- if .Values.kerberoshub.api.serviceEnabled }}
apiVersion: v1
kind: Service
@@ -121,22 +119,7 @@ spec:
template:
metadata:
annotations:
checksum/config-mongodb: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
{{- if and .Values.classificationCatalogEnabled (not .Values.classificationCatalogExistingConfigMap) (not $catalogReplacement) }}
checksum/classification-catalog: {{ include (print $.Template.BasePath "/configMaps/catalogs/classifications.yaml") . | sha256sum }}
{{- end }}
{{- if include "kerberoshub.deviceTags.system.enabled" . }}
checksum/device-system-tags: {{ include (print $.Template.BasePath "/configMaps/catalogs/device-system-tags.yaml") . | sha256sum }}
{{- end }}
{{- if and $workflowConfiguration.enabled $workflowConfiguration.includeDefaults (not (hasKey $workflowConfiguration.replacements "workflow-contracts/start.yaml")) }}
checksum/workflow-configuration: {{ include (print $.Template.BasePath "/configMaps/workflow-contracts/start.yaml") . | sha256sum }}
{{- end }}
{{- if and $workflowConfiguration.enabled $workflowConfiguration.includeDefaults (not (hasKey $workflowConfiguration.replacements "workflow-contracts/anpr.yaml")) }}
checksum/workflow-contract-anpr: {{ include (print $.Template.BasePath "/configMaps/workflow-contracts/anpr.yaml") . | sha256sum }}
{{- end }}
{{- if and $workflowConfiguration.enabled $workflowConfiguration.includeDefaults (not (hasKey $workflowConfiguration.replacements "workflow-contracts/forwarder.yaml")) }}
checksum/workflow-contract-forwarder: {{ include (print $.Template.BasePath "/configMaps/workflow-contracts/forwarder.yaml") . | sha256sum }}
{{- end }}
checksum/config-mongodb: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: hub-api
spec:
@@ -148,67 +131,8 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $serverTLS := .Values.kerberoshub.api.serverTLS }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- $classificationCatalogEnabled := .Values.classificationCatalogEnabled }}
{{- $deviceSystemTagsEnabled := include "kerberoshub.deviceTags.system.enabled" . }}
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled $deviceSystemTagsEnabled .Values.kerberoshub.api.volumes (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
{{- if or .Values.kerberoshub.api.volumes (and $serverTLS.enabled $serverTLS.secretName) }}
volumes:
{{- if $workflowConfiguration.enabled }}
- name: workflow-configuration
projected:
sources:
{{- if $workflowConfiguration.includeDefaults }}
{{- if not (hasKey $workflowConfiguration.replacements "workflow-contracts/start.yaml") }}
- configMap:
name: {{ printf "%s-workflow-configuration" .Release.Name | trunc 63 | trimSuffix "-" }}
items:
- key: start.yaml
path: workflow-contracts/start.yaml
{{- end }}
{{- if not (hasKey $workflowConfiguration.replacements "workflow-contracts/anpr.yaml") }}
- configMap:
name: {{ include "hub.workflowConfiguration.anpr.configMapName" . }}
items:
- key: anpr.yaml
path: workflow-contracts/anpr.yaml
{{- end }}
{{- if not (hasKey $workflowConfiguration.replacements "workflow-contracts/forwarder.yaml") }}
- configMap:
name: {{ include "hub.workflowConfiguration.forwarder.configMapName" . }}
items:
- key: forwarder.yaml
path: workflow-contracts/forwarder.yaml
{{- end }}
{{- if not $catalogReplacement }}
- configMap:
name: {{ include "hub.classificationCatalog.configMapName" . }}
items:
- key: classifications.json
path: catalogs/classifications.json
{{- end }}
{{- end }}
{{- range $workflowConfiguration.configMaps }}
- configMap:
name: {{ .name | quote }}
items:
{{- toYaml .items | nindent 20 }}
{{- end }}
{{- end }}
{{- if $classificationCatalogEnabled }}
- name: classification-catalog
configMap:
name: {{ include "hub.classificationCatalog.configMapName" . }}
{{- if or .Values.classificationCatalogExistingConfigMap $catalogReplacement }}
items:
- key: {{ default "classifications.json" $catalogReplacement.key | quote }}
path: classifications.json
{{- end }}
{{- end }}
{{- if $deviceSystemTagsEnabled }}
- name: device-system-tags
configMap:
name: device-system-tags
{{- end }}
{{- with .Values.kerberoshub.api.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
@@ -217,9 +141,6 @@ spec:
secret:
secretName: {{ $serverTLS.secretName }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberoshub.api.topologySpreadConstraints }}
topologySpreadConstraints:
@@ -236,23 +157,8 @@ spec:
ports:
- containerPort: 80
name: http
{{- if or $workflowConfiguration.enabled $classificationCatalogEnabled $deviceSystemTagsEnabled .Values.kerberoshub.api.volumeMounts (and $serverTLS.enabled $serverTLS.secretName) (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
{{- if or .Values.kerberoshub.api.volumeMounts (and $serverTLS.enabled $serverTLS.secretName) }}
volumeMounts:
{{- if $workflowConfiguration.enabled }}
- name: workflow-configuration
mountPath: /etc/kerberos/configuration
readOnly: true
{{- end }}
{{- if $classificationCatalogEnabled }}
- name: classification-catalog
mountPath: /etc/kerberos/classifications
readOnly: true
{{- end }}
{{- if $deviceSystemTagsEnabled }}
- name: device-system-tags
mountPath: /etc/kerberos/device-tags
readOnly: true
{{- end }}
{{- with .Values.kerberoshub.api.volumeMounts}}
{{- toYaml . | nindent 12 }}
{{- end }}
@@ -261,26 +167,12 @@ spec:
mountPath: {{ $serverTLS.mountPath }}
readOnly: true
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
# Mongodb - loaded from ConfigMap
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-api") | nindent 12 }}
{{- if $classificationCatalogEnabled }}
- name: CLASSIFICATION_CATALOG_FILE
value: /etc/kerberos/classifications/classifications.json
{{- end }}
{{- if $deviceSystemTagsEnabled }}
# System tag catalog (deviceTags.system.catalog): the only system
# tags owners can assign. Unset (disabled) disables system tags.
- name: DEVICE_SYSTEM_TAGS_FILE
value: /etc/kerberos/device-tags/system-tags.json
{{- end }}
- name: ENVIRONMENT
value: "{{ .Values.environment }}"
- name: READ_ONLY
@@ -295,26 +187,6 @@ spec:
value: "{{ .Values.kerberoshub.api.schema }}://{{ .Values.kerberoshub.api.url }}"
- name: PUBLIC_URL
value: "{{ .Values.kerberoshub.frontend.schema }}://{{ .Values.kerberoshub.frontend.url }}"
- name: REFRESH_COOKIE_SECURE
value: {{ eq .Values.kerberoshub.api.schema "https" | quote }}
{{- $corsOrigins := list (printf "%s://%s" .Values.kerberoshub.frontend.schema .Values.kerberoshub.frontend.url) }}
{{- with .Values.kerberoshub.frontend.legacyUrl }}
{{- $corsOrigins = append $corsOrigins (printf "%s://%s" $.Values.kerberoshub.frontend.schema .) }}
{{- end }}
{{- range .Values.kerberoshub.frontend.domains }}
{{- $corsOrigins = append $corsOrigins (printf "%s://%s" $.Values.kerberoshub.frontend.schema .) }}
{{- end }}
{{- if and .Values.kerberoshub.frontend.multiTenant .Values.kerberoshub.frontend.tenantBaseDomain }}
{{- $corsOrigins = append $corsOrigins (printf "%s://*.%s" .Values.kerberoshub.frontend.schema .Values.kerberoshub.frontend.tenantBaseDomain) }}
{{- end }}
{{- if and .Values.kerberoshub.frontend.demoEnabled .Values.kerberoshub.frontend.demoUrl }}
{{- $corsOrigins = append $corsOrigins (printf "%s://%s" .Values.kerberoshub.frontend.schema .Values.kerberoshub.frontend.demoUrl) }}
{{- end }}
{{- range .Values.kerberoshub.api.corsAllowedOrigins }}
{{- $corsOrigins = append $corsOrigins . }}
{{- end }}
- name: CORS_ALLOWED_ORIGINS
value: {{ join "," $corsOrigins | quote }}
{{ if .Values.isPrivate }}
- name: KERBEROS_PRIVATE_CLOUD
value: "true"
@@ -361,27 +233,6 @@ spec:
- name: KERBEROS_JWT_SECRET
value: "{{ .Values.kerberoshub.api.jwtSecret }}"
# Temporarily stop serving the polled GET /devices list (204, no DB reads).
- name: DISABLE_AGENT_HEARTBEAT
value: {{ .Values.kerberoshub.api.disableAgentHeartbeat | default false | quote }}
# Media proxy: hide Vault/storage endpoints behind hub-api URLs.
{{- $mediaProxy := .Values.kerberoshub.api.mediaProxy | default dict }}
- name: MEDIA_PROXY_ENABLED
value: {{ $mediaProxy.enabled | default false | quote }}
{{- if $mediaProxy.publicUrl }}
- name: MEDIA_PROXY_PUBLIC_URL
value: {{ $mediaProxy.publicUrl | quote }}
{{- end }}
{{- if $mediaProxy.key }}
- name: MEDIA_PROXY_KEY
value: {{ $mediaProxy.key | quote }}
{{- end }}
{{- if $mediaProxy.ttl }}
- name: MEDIA_PROXY_TTL
value: {{ $mediaProxy.ttl | quote }}
{{- end }}
# SSO (OIDC) setup
- name: SSO_DOMAINS
value: "{{- range .Values.kerberoshub.api.sso }}{{ .domain }};{{- end }}"
@@ -408,22 +259,6 @@ spec:
- name: QUEUE_NAME
value: "{{ .Values.queueName }}"
# Deployment-global workflow definitions (WORKFLOW_DEFINITIONS): the
# SAME set the workflows engine consumes, assembled from the enabled
# definitions under kerberoshub.workflows.definitions (see
# kerberos-pipeline/_workflows-helpers.tpl). hub-api reads these
# read-only to surface config workflows alongside the user workflows
# it stores in the database; the config workflows are never persisted.
- name: WORKFLOW_DEFINITIONS
value: {{ include "kerberoshub.workflows.workflowDefinitions" . | quote }}
# Deployment service routing catalog used by API-owned embedded
# workflows (for example the one-stage case redaction modal flow).
- name: WORKFLOW_STAGE_QUEUES
value: {{ include "kerberoshub.workflows.stageQueues" . | quote }}
# Stages tenants may place in the workflow editor (see workflows.editorStages).
- name: WORKFLOW_EDITOR_STAGES
value: {{ .Values.kerberoshub.workflows.editorStages | default list | toJson | quote }}
# Stripe for billing
- name: STRIPE_KEY
value: "{{ .Values.kerberoshub.api.stripe.privateKey }}"
@@ -436,15 +271,6 @@ spec:
- name: MFA_ISSUER
value: "{{ .Values.kerberoshub.api.mfaIssuer }}"
{{- if .Values.kerberoshub.api.passkeys.enabled }}
- name: PASSKEY_RP_ID
value: {{ required "kerberoshub.api.passkeys.rpId is required when passkeys are enabled" .Values.kerberoshub.api.passkeys.rpId | quote }}
- name: PASSKEY_ORIGINS
value: {{ required "kerberoshub.api.passkeys.origins is required when passkeys are enabled" .Values.kerberoshub.api.passkeys.origins | join "," | quote }}
- name: PASSKEY_RP_NAME
value: {{ .Values.kerberoshub.api.passkeys.rpName | quote }}
{{- end }}
# AWS (Legacy, use Kerberos Vault instead)
- name: AWS_REGION
value: "{{ .Values.kerberoshub.api.aws.region }}"
@@ -493,14 +319,6 @@ spec:
value: "{{ .Values.rabbitmq.username }}"
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
- name: AUDIT_ENABLED
value: {{ and .Values.audit.enabled .Values.kerberoshub.api.audit.enabled | quote }}
{{- if and .Values.audit.enabled .Values.kerberoshub.api.audit.enabled }}
- name: AUDIT_QUEUE
value: {{ .Values.audit.intake.queue | quote }}
- name: AUDIT_DEADLETTER_QUEUE
value: {{ .Values.audit.intake.deadletterQueue | quote }}
{{- end }}
# Slack notifications (this will send events/logs to a specific channel).
- name: SLACK_ENABLED
@@ -535,14 +353,6 @@ spec:
value: "{{ .Values.email.templates.share }}"
- name: SHARE_TITLE
value: "{{ .Values.email.templates.shareTitle }}"
- name: CASE_SHARE_TEMPLATE
value: "{{ .Values.email.templates.caseShare }}"
- name: CASE_SHARE_TITLE
value: "{{ .Values.email.templates.caseShareTitle }}"
- name: CASE_SHARE_OTP_TEMPLATE
value: "{{ .Values.email.templates.caseShareOtp }}"
- name: CASE_SHARE_OTP_TITLE
value: "{{ .Values.email.templates.caseShareOtpTitle }}"
- name: ASSIGN_TASK_TEMPLATE
value: "{{ .Values.email.templates.assignTask }}"
- name: ASSIGN_TASK_TITLE
@@ -589,16 +399,15 @@ spec:
- name: VAULT_SPRITE_SECRET_KEY
value: "{{ .Values.kerberosvault.sprite.secretKey }}"
- name: VAULT_SPRITE_INTERVAL
value: "{{ .Values.kerberospipeline.sprite.interval }}"
value: "{{ .Values.kerberosvault.sprite.interval }}"
- name: VAULT_SPRITE_WIDTH
value: "{{ .Values.kerberospipeline.sprite.width }}"
value: "{{ .Values.kerberosvault.sprite.width }}"
- name: VAULT_SPRITE_HEIGHT
value: "{{ .Values.kerberospipeline.sprite.height }}"
value: "{{ .Values.kerberosvault.sprite.height }}"
{{- if .Values.kerberoshub.extraEnv }}
{{- toYaml .Values.kerberoshub.extraEnv | nindent 12 }}
{{- end }}
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -606,6 +415,4 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.apiSamplerEnv" $ | trim | nindent 12 }}
{{- end }}
{{- end }}
@@ -1,18 +0,0 @@
{{- if and .Values.audit.enabled .Values.kerberoshub.audit.serviceMonitor.enabled -}}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: hub-audit-servicemonitor
namespace: {{ .Release.Namespace }}
labels:
service: hub-audit
release: prometheus
spec:
selector:
matchLabels:
service: hub-audit
endpoints:
- port: metrics
interval: {{ .Values.kerberoshub.audit.serviceMonitor.interval }}
path: /metrics
{{- end }}
@@ -1,167 +0,0 @@
{{- if .Values.audit.enabled -}}
{{- if ne (upper .Values.queueProvider) "RABBITMQ" -}}
{{- fail "kerberoshub.audit currently requires queueProvider=RABBITMQ" -}}
{{- end -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: hub-audit
namespace: {{ .Release.Namespace }}
spec:
replicas: {{ .Values.kerberoshub.audit.replicas }}
selector:
matchLabels:
app: hub-audit
minReadySeconds: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
annotations:
checksum/config-mongodb: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: hub-audit
spec:
terminationGracePeriodSeconds: {{ .Values.kerberoshub.audit.terminationGracePeriodSeconds }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
volumes:
- name: destinations
configMap:
name: hub-audit
{{- range $index, $destination := .Values.kerberoshub.audit.destinations }}
{{- $bearer := default dict $destination.bearerTokenSecret }}
{{- $secretHeaders := default dict $destination.secretHeaders }}
{{- if or (gt (len $bearer) 0) (gt (len $secretHeaders) 0) }}
- name: audit-dest-{{ sha256sum $destination.id | trunc 12 }}
projected:
sources:
{{- if gt (len $bearer) 0 }}
- secret:
name: {{ required (printf "bearerTokenSecret.name is required for destination %s" $destination.id) $bearer.name | quote }}
items:
- key: {{ default "token" $bearer.key | quote }}
path: bearer-{{ sha256sum (printf "%s:%s" $bearer.name (default "token" $bearer.key)) | trunc 12 }}
{{- end }}
{{- range $headerName, $secret := $secretHeaders }}
- secret:
name: {{ required (printf "secretName is required for destination %s header %s" $destination.id $headerName) $secret.secretName | quote }}
items:
- key: {{ required (printf "secretKey is required for destination %s header %s" $destination.id $headerName) $secret.secretKey | quote }}
path: header-{{ sha256sum (printf "%s:%s:%s" $headerName $secret.secretName $secret.secretKey) | trunc 12 }}
{{- end }}
{{- end }}
{{- end }}
{{- with .Values.kerberoshub.audit.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- with .Values.kerberoshub.audit.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: hub-audit
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberoshub.audit.repository }}:{{ .Values.kerberoshub.audit.tag }}"
imagePullPolicy: {{ .Values.kerberoshub.audit.pullPolicy }}
{{- with .Values.kerberoshub.audit.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: metrics
containerPort: 2112
protocol: TCP
readinessProbe:
httpGet:
path: /healthz
port: metrics
livenessProbe:
httpGet:
path: /healthz
port: metrics
volumeMounts:
- name: destinations
mountPath: /etc/hub-audit
readOnly: true
{{- range $index, $destination := .Values.kerberoshub.audit.destinations }}
{{- $bearer := default dict $destination.bearerTokenSecret }}
{{- $secretHeaders := default dict $destination.secretHeaders }}
{{- if or (gt (len $bearer) 0) (gt (len $secretHeaders) 0) }}
- name: audit-dest-{{ sha256sum $destination.id | trunc 12 }}
mountPath: /var/run/secrets/audit-destinations/{{ $destination.id }}
readOnly: true
{{- end }}
{{- end }}
{{- with .Values.kerberoshub.audit.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-audit") | nindent 12 }}
- name: RABBITMQ_HOST
value: {{ .Values.rabbitmq.host | quote }}
- name: RABBITMQ_EXCHANGE
value: {{ .Values.rabbitmq.exchange | quote }}
- name: RABBITMQ_USERNAME
value: {{ .Values.rabbitmq.username | quote }}
- name: RABBITMQ_PASSWORD
value: {{ .Values.rabbitmq.password | quote }}
- name: AUDIT_QUEUE
value: {{ .Values.audit.intake.queue | quote }}
- name: AUDIT_DEADLETTER_QUEUE
value: {{ .Values.audit.intake.deadletterQueue | quote }}
- name: AUDIT_MAX_RETRIES
value: {{ .Values.audit.intake.maxRetries | quote }}
- name: AUDIT_PREFETCH_COUNT
value: {{ .Values.audit.intake.prefetchCount | quote }}
- name: AUDIT_PERSIST_TIMEOUT
value: {{ .Values.audit.intake.persistTimeout | quote }}
- name: DISPATCH_INTERVAL
value: {{ .Values.kerberoshub.audit.dispatchInterval | quote }}
- name: LEASE_DURATION
value: {{ .Values.kerberoshub.audit.leaseDuration | quote }}
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
{{- with .Values.kerberoshub.audit.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.kerberoshub.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}
---
apiVersion: v1
kind: Service
metadata:
name: hub-audit
namespace: {{ .Release.Namespace }}
labels:
app: hub-audit
service: hub-audit
spec:
ports:
- name: metrics
port: 2112
targetPort: metrics
protocol: TCP
selector:
app: hub-audit
{{- end }}
@@ -18,14 +18,10 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: hub-cleanup
spec:
{{- with .Values.kerberoshub.cleanup.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -33,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberoshub.cleanup.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberoshub.cleanup.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberoshub.cleanup.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -51,30 +41,20 @@ spec:
- name: hub-cleanup
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberoshub.cleanup.repository }}:{{ .Values.kerberoshub.cleanup.tag }}"
imagePullPolicy: {{ .Values.kerberoshub.cleanup.pullPolicy }}
{{- with .Values.kerberoshub.cleanup.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.kerberoshub.cleanup.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberoshub.cleanup.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberoshub.cleanup.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
ports:
- containerPort: 8080
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-cleanup") | nindent 12 }}
- name: MODE
value: "{{ .Values.kerberoshub.cleanup.mode }}"
- name: LOG_LEVEL
@@ -117,10 +97,6 @@ spec:
value: "{{ .Values.kerberoshub.cleanup.globalPassDeleteBudget }}"
- name: DEFAULT_TASK_RETENTION_DAYS
value: "{{ .Values.kerberoshub.cleanup.defaultTaskRetentionDays }}"
- name: AUDIT_EVENT_RETENTION_DAYS
value: "{{ .Values.kerberoshub.cleanup.auditEventRetentionDays }}"
- name: WORKFLOW_RUN_RETENTION_DAYS
value: "{{ .Values.kerberoshub.cleanup.workflowRunRetentionDays | default "0" }}"
{{- if .Values.kerberoshub.extraEnv }}
{{- toYaml .Values.kerberoshub.extraEnv | nindent 12 }}
{{- end }}
@@ -10,7 +10,7 @@ spec:
ports:
- protocol: TCP
port: 80
targetPort: http
targetPort: 80
name: http
selector:
app: hub-frontend-demo
@@ -101,16 +101,12 @@ spec:
- name: hub-frontend-demo
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberoshub.frontend.repository }}:{{ .Values.kerberoshub.frontend.tag }}"
imagePullPolicy: {{ .Values.kerberoshub.frontend.pullPolicy }}
{{- with .Values.kerberoshub.frontend.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.kerberoshub.frontend.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- containerPort: {{ .Values.kerberoshub.frontend.containerPort | default 80 }}
- containerPort: 80
name: http
{{- with .Values.kerberoshub.frontend.volumeMounts}}
volumeMounts:
@@ -196,12 +192,6 @@ spec:
# Google maps for using and displaying cameras, sites on a map
- name: GOOGLEMAPS_KEY
value: "{{ .Values.kerberoshub.frontend.googlemaps.apikey }}"
- name: GOOGLEMAPS_PLACES_API
value: "{{ .Values.kerberoshub.frontend.googlemaps.placesApi }}"
# features > chart
- name: CHART_COLORS
value: {{ .Values.kerberoshub.frontend.features.chart.colors | toJson | quote }}
# Zendesk for support
- name: ZENDESK_URL
@@ -239,36 +229,8 @@ spec:
value: "{{ .Values.kerberoshub.frontend.features.case.enabled }}"
- name: FEATURE_WORKFLOWS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.workflows.enabled }}"
- name: FEATURE_AUDIT_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.audit.enabled }}"
- name: FEATURE_DAY_OVERVIEW_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.dayOverview.enabled }}"
- name: FEATURE_DEVICE_ANALYTICS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.devices.analyticsEnabled }}"
- name: FEATURE_DASHBOARD_SITES_FULLSCREEN_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.dashboard.sitesFullscreenEnabled }}"
- name: FEATURE_DEVICE_DEVELOPER_TOOLS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.devices.developerToolsEnabled }}"
- name: FEATURE_ORGANISATIONS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.organisations.enabled }}"
- name: FEATURE_ORGANISATION_SWITCHER_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.organisations.switcherEnabled }}"
- name: FEATURE_ORGANISATION_CREATION_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.organisations.creationEnabled }}"
- name: FEATURE_ORGANISATION_SETTINGS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.organisations.settingsEnabled }}"
- name: FEATURE_PROJECTS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.projects.enabled }}"
- name: FEATURE_PROJECT_SWITCHER_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.projects.switcherEnabled }}"
- name: FEATURE_PROJECT_CREATION_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.projects.creationEnabled }}"
- name: FEATURE_PROJECT_SETTINGS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.projects.settingsEnabled }}"
- name: FEATURE_DARK_MODE
value: "{{ .Values.kerberoshub.frontend.features.darkMode }}"
- name: FEATURE_SPLASH_SCREEN_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.splashScreen.enabled }}"
- name: FEATURE_LANDING_PAGE
value: "{{ .Values.kerberoshub.frontend.features.landingPage }}"
@@ -279,20 +241,6 @@ spec:
value: "{{ .Values.kerberoshub.frontend.features.i18n.defaultLanguage }}"
# features > liveview
- name: FEATURE_LIVE_STREAM_MODE
value: "{{ .Values.kerberoshub.frontend.features.liveview.liveStreamMode }}"
- name: FEATURE_HLS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.liveview.hlsEnabled }}"
- name: FEATURE_MOQ_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.liveview.moqEnabled }}"
- name: FEATURE_REMOTE_RECORDING_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.liveview.remoteRecordingEnabled }}"
- name: FEATURE_LIVE_VIEW_DEVICE_STATUS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.liveview.deviceStatusEnabled }}"
- name: MOQ_RELAY_URL
value: "{{ .Values.kerberoshub.frontend.features.liveview.moqRelayUrl }}"
- name: MOQ_BROADCAST_PREFIX
value: "{{ .Values.kerberoshub.frontend.features.liveview.moqBroadcastPrefix }}"
- name: FEATURE_LIVEVIEW_PAGINATION_MODE
value: "{{ .Values.kerberoshub.frontend.features.liveview.paginationMode }}"
- name: FEATURE_LIVEVIEW_PAGE_SIZE
@@ -307,26 +255,6 @@ spec:
# features > floorplan
- name: FEATURE_FLOORPLAN_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.floorplan.enabled }}"
# features > map
- name: MAP_TILE_URL_LIGHT
value: "{{ .Values.kerberoshub.frontend.features.map.tileUrlLight }}"
- name: MAP_TILE_URL_DARK
value: "{{ .Values.kerberoshub.frontend.features.map.tileUrlDark }}"
- name: MAP_ATTRIBUTION
value: "{{ .Values.kerberoshub.frontend.features.map.attribution }}"
- name: MAP_OVERLAY_TILE_URL
value: "{{ .Values.kerberoshub.frontend.features.map.overlayTileUrl }}"
- name: MAP_OVERLAY_API_KEY
value: "{{ .Values.kerberoshub.frontend.features.map.overlayApiKey }}"
- name: MAP_OVERLAY_ATTRIBUTION
value: "{{ .Values.kerberoshub.frontend.features.map.overlayAttribution }}"
- name: MAP_OVERLAY_MIN_ZOOM
value: "{{ .Values.kerberoshub.frontend.features.map.overlayMinZoom }}"
- name: MAP_OVERLAY_MAX_ZOOM
value: "{{ .Values.kerberoshub.frontend.features.map.overlayMaxZoom }}"
- name: MAP_OVERLAY_OPACITY
value: "{{ .Values.kerberoshub.frontend.features.map.overlayOpacity }}"
- name: COLOR_TRACK_BOX
value: "{{ .Values.kerberoshub.frontend.features.floorplan.colorTrackBox }}"
- name: COLOR_TRACK_BOX_HOVER
@@ -360,9 +288,7 @@ spec:
# features > face redaction
- name: FEATURE_FACE_REDACTION_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.faceRedaction.enabled }}"
- name: FEATURE_FACE_REDACTION_CLASSIFIER_TRACKS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.faceRedaction.classifierTracksEnabled }}"
value: "{{ .Values.kerberoshub.frontend.features.faceRedaction.enabled }}"
# features > media
- name: FEATURE_MEDIA_FILTER_DATE_ENABLED
@@ -377,22 +303,14 @@ spec:
value: "{{ .Values.kerberoshub.frontend.features.media.filter.objectDetection.enabled }}"
- name: FEATURE_MEDIA_FILTER_STAR_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.star.enabled }}"
- name: FEATURE_MEDIA_FILTER_ANALYSIS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.analysis.enabled }}"
- name: FEATURE_MEDIA_FILTER_REGION_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.region.enabled }}"
- name: FEATURE_MEDIA_FILTER_SORT_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.sort.enabled }}"
- name: FEATURE_MEDIA_FILTER_CATEGORIES_ENABLED
- name: FEATURE_MEDIA_FILTER_CATEGORY_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.category.enabled }}"
- name: FEATURE_MEDIA_FILTER_MARKERS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.markers.enabled }}"
- name: FEATURE_MEDIA_FILTER_MARKER_OPTIONS_BY_DATE_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.markerOptionsByDate.enabled }}"
- name: FEATURE_MEDIA_FILTER_MARKER_CATEGORY_PRIORITY_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.markerCategoryPriority.enabled }}"
- name: FEATURE_MEDIA_FILTER_MARKER_CATEGORY_PRIORITY_CATEGORIES
value: {{ .Values.kerberoshub.frontend.features.media.filter.markerCategoryPriority.categories | toJson | replace "\\" "\\\\" | replace "'" "\\u0027" | quote }}
- name: FEATURE_MEDIA_FILTER_EVENTS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.events.enabled }}"
- name: FEATURE_MEDIA_FILTER_TAGS_ENABLED
@@ -11,7 +11,7 @@ spec:
ports:
- protocol: TCP
port: 80
targetPort: http
targetPort: 80
name: http
selector:
app: hub-frontend
@@ -182,16 +182,12 @@ spec:
- name: hub-frontend
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberoshub.frontend.repository }}:{{ .Values.kerberoshub.frontend.tag }}"
imagePullPolicy: {{ .Values.kerberoshub.frontend.pullPolicy }}
{{- with .Values.kerberoshub.frontend.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.kerberoshub.frontend.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- containerPort: {{ .Values.kerberoshub.frontend.containerPort | default 80 }}
- containerPort: 80
name: http
{{- with .Values.kerberoshub.frontend.volumeMounts}}
volumeMounts:
@@ -279,8 +275,6 @@ spec:
# Google maps for using and displaying cameras, sites on a map
- name: GOOGLEMAPS_KEY
value: "{{ .Values.kerberoshub.frontend.googlemaps.apikey }}"
- name: GOOGLEMAPS_PLACES_API
value: "{{ .Values.kerberoshub.frontend.googlemaps.placesApi }}"
# Zendesk for support
- name: ZENDESK_URL
@@ -318,36 +312,8 @@ spec:
value: "{{ .Values.kerberoshub.frontend.features.case.enabled }}"
- name: FEATURE_WORKFLOWS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.workflows.enabled }}"
- name: FEATURE_AUDIT_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.audit.enabled }}"
- name: FEATURE_DAY_OVERVIEW_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.dayOverview.enabled }}"
- name: FEATURE_DEVICE_ANALYTICS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.devices.analyticsEnabled }}"
- name: FEATURE_DASHBOARD_SITES_FULLSCREEN_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.dashboard.sitesFullscreenEnabled }}"
- name: FEATURE_DEVICE_DEVELOPER_TOOLS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.devices.developerToolsEnabled }}"
- name: FEATURE_ORGANISATIONS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.organisations.enabled }}"
- name: FEATURE_ORGANISATION_SWITCHER_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.organisations.switcherEnabled }}"
- name: FEATURE_ORGANISATION_CREATION_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.organisations.creationEnabled }}"
- name: FEATURE_ORGANISATION_SETTINGS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.organisations.settingsEnabled }}"
- name: FEATURE_PROJECTS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.projects.enabled }}"
- name: FEATURE_PROJECT_SWITCHER_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.projects.switcherEnabled }}"
- name: FEATURE_PROJECT_CREATION_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.projects.creationEnabled }}"
- name: FEATURE_PROJECT_SETTINGS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.projects.settingsEnabled }}"
- name: FEATURE_DARK_MODE
value: "{{ .Values.kerberoshub.frontend.features.darkModeEnabled }}"
- name: FEATURE_SPLASH_SCREEN_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.splashScreen.enabled }}"
- name: FEATURE_LANDING_PAGE
value: "{{ .Values.kerberoshub.frontend.features.landingPage }}"
@@ -360,20 +326,6 @@ spec:
# features > liveview
- name: FEATURE_DEFAULT_STREAM_MODE
value: "{{ .Values.kerberoshub.frontend.features.liveview.defaultStreamMode }}"
- name: FEATURE_LIVE_STREAM_MODE
value: "{{ .Values.kerberoshub.frontend.features.liveview.liveStreamMode }}"
- name: FEATURE_HLS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.liveview.hlsEnabled }}"
- name: FEATURE_MOQ_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.liveview.moqEnabled }}"
- name: FEATURE_REMOTE_RECORDING_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.liveview.remoteRecordingEnabled }}"
- name: FEATURE_LIVE_VIEW_DEVICE_STATUS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.liveview.deviceStatusEnabled }}"
- name: MOQ_RELAY_URL
value: "{{ .Values.kerberoshub.frontend.features.liveview.moqRelayUrl }}"
- name: MOQ_BROADCAST_PREFIX
value: "{{ .Values.kerberoshub.frontend.features.liveview.moqBroadcastPrefix }}"
- name: FEATURE_LIVEVIEW_PAGINATION_MODE
value: "{{ .Values.kerberoshub.frontend.features.liveview.paginationMode }}"
- name: FEATURE_LIVEVIEW_PAGE_SIZE
@@ -396,18 +348,6 @@ spec:
value: "{{ .Values.kerberoshub.frontend.features.map.tileUrlDark }}"
- name: MAP_ATTRIBUTION
value: "{{ .Values.kerberoshub.frontend.features.map.attribution }}"
- name: MAP_OVERLAY_TILE_URL
value: "{{ .Values.kerberoshub.frontend.features.map.overlayTileUrl }}"
- name: MAP_OVERLAY_API_KEY
value: "{{ .Values.kerberoshub.frontend.features.map.overlayApiKey }}"
- name: MAP_OVERLAY_ATTRIBUTION
value: "{{ .Values.kerberoshub.frontend.features.map.overlayAttribution }}"
- name: MAP_OVERLAY_MIN_ZOOM
value: "{{ .Values.kerberoshub.frontend.features.map.overlayMinZoom }}"
- name: MAP_OVERLAY_MAX_ZOOM
value: "{{ .Values.kerberoshub.frontend.features.map.overlayMaxZoom }}"
- name: MAP_OVERLAY_OPACITY
value: "{{ .Values.kerberoshub.frontend.features.map.overlayOpacity }}"
- name: COLOR_TRACK_BOX
value: "{{ .Values.kerberoshub.frontend.features.floorplan.colorTrackBox }}"
@@ -437,8 +377,6 @@ spec:
value: "{{ .Values.kerberoshub.frontend.colorDeviceMarkerBorder }}"
# features > chart
- name: CHART_COLORS
value: {{ .Values.kerberoshub.frontend.features.chart.colors | toJson | quote }}
- name: COLOR_CHART_SELECTION_FILL
value: "{{ .Values.kerberoshub.frontend.features.chart.colorChartSelectionFill }}"
- name: COLOR_CHART_SELECTION_STROKE
@@ -452,9 +390,7 @@ spec:
# features > face redaction
- name: FEATURE_FACE_REDACTION_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.faceRedaction.enabled }}"
- name: FEATURE_FACE_REDACTION_CLASSIFIER_TRACKS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.faceRedaction.classifierTracksEnabled }}"
value: "{{ .Values.kerberoshub.frontend.features.faceRedaction.enabled }}"
# features > media
- name: FEATURE_MEDIA_FILTER_DATE_ENABLED
@@ -469,22 +405,14 @@ spec:
value: "{{ .Values.kerberoshub.frontend.features.media.filter.objectDetection.enabled }}"
- name: FEATURE_MEDIA_FILTER_STAR_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.star.enabled }}"
- name: FEATURE_MEDIA_FILTER_ANALYSIS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.analysis.enabled }}"
- name: FEATURE_MEDIA_FILTER_REGION_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.region.enabled }}"
- name: FEATURE_MEDIA_FILTER_SORT_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.sort.enabled }}"
- name: FEATURE_MEDIA_FILTER_CATEGORIES_ENABLED
- name: FEATURE_MEDIA_FILTER_CATEGORY_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.category.enabled }}"
- name: FEATURE_MEDIA_FILTER_MARKERS_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.markers.enabled }}"
- name: FEATURE_MEDIA_FILTER_MARKER_OPTIONS_BY_DATE_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.markerOptionsByDate.enabled }}"
- name: FEATURE_MEDIA_FILTER_MARKER_CATEGORY_PRIORITY_ENABLED
value: "{{ .Values.kerberoshub.frontend.features.media.filter.markerCategoryPriority.enabled }}"
- name: FEATURE_MEDIA_FILTER_MARKER_CATEGORY_PRIORITY_CATEGORIES
value: {{ .Values.kerberoshub.frontend.features.media.filter.markerCategoryPriority.categories | toJson | replace "\\" "\\\\" | replace "'" "\\u0027" | quote }}
- name: FEATURE_MEDIA_FILTER_DEFAULT_VIEW
value: "{{ .Values.kerberoshub.frontend.features.media.filter.defaultView }}"
- name: FEATURE_MEDIA_FILTER_EVENTS_ENABLED
@@ -18,14 +18,10 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: hub-monitor-device
spec:
{{- with .Values.kerberoshub.monitordevice.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -33,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberoshub.monitordevice.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberoshub.monitordevice.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberoshub.monitordevice.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -51,32 +41,20 @@ spec:
- name: hub-monitor-device
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberoshub.monitordevice.repository }}:{{ .Values.kerberoshub.monitordevice.tag }}"
imagePullPolicy: {{ .Values.kerberoshub.monitordevice.pullPolicy }}
{{- with .Values.kerberoshub.monitordevice.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.kerberoshub.monitordevice.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberoshub.monitordevice.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberoshub.monitordevice.volumeMounts}}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-monitor-device") | nindent 12 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberoshub.monitordevice.logLevel }}"
- name: DEVICE_SCAN_INTERVAL_SECONDS
value: "{{ .Values.kerberoshub.monitordevice.scanIntervalSeconds | default 60 }}"
- name: READ_ONLY
value: "{{ .Values.readonly }}"
# Mail settings
@@ -92,13 +70,6 @@ spec:
value: "{{ .Values.email.templates.device }}"
- name: DEVICE_TITLE
value: "{{ .Values.email.templates.deviceTitle }}"
- name: DEVICE_GROUP_TEMPLATE
value: "{{ .Values.email.templates.deviceGroup | default "device_group" }}"
- name: DEVICE_GROUP_TITLE
value: "{{ .Values.email.templates.deviceGroupTitle | default "[Device] Several cameras changed status" }}"
# Base URL for the link in grouped device notifications.
- name: PUBLIC_URL
value: "{{ .Values.kerberoshub.frontend.schema }}://{{ .Values.kerberoshub.frontend.url }}"
# - Plain SMTP
- name: SMTP_SERVER
@@ -18,7 +18,7 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: hub-reactivate-subscription
spec:
@@ -26,16 +26,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberoshub.reactivate.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberoshub.reactivate.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberoshub.reactivate.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -44,20 +38,14 @@ spec:
- name: hub-reactivate-subscription
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberoshub.reactivate.repository }}:{{ .Values.kerberoshub.reactivate.tag }}"
imagePullPolicy: {{ .Values.kerberoshub.reactivate.pullPolicy }}
{{- if or .Values.kerberoshub.reactivate.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberoshub.reactivate.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-reactivatesubscriptions") | nindent 12 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberoshub.reactivate.logLevel }}"
- name: READ_ONLY
@@ -1,154 +1,42 @@
{{/*
Reserve every effective identity, including disabled definitions, so enabling a
workflow later cannot silently alias another workflow's runs or references.
*/}}
{{- define "kerberoshub.workflows.validateDefinitions" -}}
{{- $identities := dict -}}
{{- range $name, $wf := .Values.kerberoshub.workflows.definitions -}}
{{- $id := sha256sum $name | trunc 24 -}}
{{- if hasKey $wf "id" -}}
{{- $invalid := printf "kerberoshub.workflows.definitions[%q].id must be a non-zero 24-character hexadecimal string (Mongo ObjectID); omit id for name-derived compatibility" $name -}}
{{- if not (kindIs "string" $wf.id) -}}
{{- fail $invalid -}}
{{- end -}}
{{- if or (not (regexMatch "^[0-9a-fA-F]{24}$" $wf.id)) (eq $wf.id "000000000000000000000000") -}}
{{- fail $invalid -}}
{{- end -}}
{{- $id = lower $wf.id -}}
{{- end -}}
{{- if hasKey $identities $id -}}
{{- fail (printf "kerberoshub.workflows.definitions: duplicate effective workflow id %q for %q and %q (including disabled definitions)" $id (index $identities $id) $name) -}}
{{- end -}}
{{- $_ := set $identities $id $name -}}
{{- end -}}
{{- include "kerberoshub.workflows.validateSystemTags" . -}}
{{- end -}}
Assemble the workflows engine stage registry (PIPELINE_STAGE_REGISTRY) as a
JSON array from every *enabled* stage under kerberoshub.workflows.stages, so the
engine's routing stays in lockstep with the deployed stage workers and the
per-stage queue cannot drift. The `stages:` block is the routing source of truth;
each stage's deployment (and its queue) lives under the matching
kerberoshub.services.<name> entry.
{{/*
Guard the definitions that can select devices by system tag. The engine reads
JSON keys case-insensitively and ignores unknown ones, so a misspelled or
re-cased key silently changes what a definition selects (a dropped
systemTags scope makes a global workflow run on every device). Therefore:
- definitions and triggers may only use the keys the engine knows, spelled
exactly (definition: id, enabled, triggers, stages; trigger: the
models.WorkflowTrigger fields);
- while deviceTags.system.enabled is false, no definition may mention system
tags anywhere (trigger systemTags, or a device.systemTags condition at any
depth, in triggers, shared conditions or stage needs), matched
case-insensitively on the whole definition;
- every system tag a trigger selects must be in deviceTags.system.catalog,
so a typo fails rendering instead of never matching a device.
Disabled definitions are checked too, so enabling one cannot fail later.
Each enabled stage contributes one descriptor:
operation defaults to the stage's map key.
dispatch defaults to "always".
queue taken from the matching services.<key>.queue (authoritative; the
same value the worker consumes via <NAME>_QUEUE). Omitted when the
service or its queue is unset, so the engine derives
"kcloud-<operation>-queue.fifo".
needs conditional stages only: the upstream dependencies (each
{operation, condition?}) carried through verbatim.
needsMode conditional stages with more than one need: how they combine —
"any" (default; fire on the first matching upstream) or "all"
(a join; fire only once every need has resolved and matched).
Carried through verbatim; omitted when unset (engine defaults any).
kind delegated-ingest stages only: the ingest handler the engine routes
the stage's typed payload through (e.g. "detection"). Carried
through verbatim; omitted when unset (engine treats the stage as
self-persisting).
*/}}
{{- define "kerberoshub.workflows.validateSystemTags" -}}
{{- include "kerberoshub.deviceTags.system.validate" . -}}
{{- $catalog := dict -}}
{{- range $tag := (include "kerberoshub.deviceTags.system.catalog" . | fromJsonArray) -}}
{{- $_ := set $catalog (toString $tag.key) true -}}
{{- end -}}
{{- $enabled := include "kerberoshub.deviceTags.system.enabled" . -}}
{{- $definitionKeys := list "id" "enabled" "triggers" "stages" -}}
{{- $triggerKeys := list "type" "edgeId" "sharedConditions" "devices" "siteIds" "groupIds" "systemTags" "classifications" "conditionMode" "conditions" "weeklySchedule" "surfaces" -}}
{{- range $name, $wf := .Values.kerberoshub.workflows.definitions -}}
{{- if $wf -}}
{{- if not (kindIs "map" $wf) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q] must be an object" $name) -}}
{{- end -}}
{{- if and (not $enabled) (contains "systemtags" (lower (toJson $wf))) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q] selects devices by system tag (systemTags or a device.systemTags condition), but deviceTags.system.enabled is false" $name) -}}
{{- end -}}
{{- range $key, $_ := $wf -}}
{{- if not (has $key $definitionKeys) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q]: unknown key %q (allowed: %s). Keys are case-sensitive; a misspelled key would be ignored" $name $key (join ", " $definitionKeys)) -}}
{{- end -}}
{{- end -}}
{{- range $i, $trigger := ($wf.triggers | default list) -}}
{{- if not (kindIs "map" $trigger) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d] must be an object" $name $i) -}}
{{- end -}}
{{- range $key, $_ := $trigger -}}
{{- if not (has $key $triggerKeys) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d]: unknown key %q (allowed: %s). Keys are case-sensitive; a misspelled key would be ignored and widen the trigger" $name $i $key (join ", " $triggerKeys)) -}}
{{- end -}}
{{- end -}}
{{- range $tag := ($trigger.systemTags | default list) -}}
{{- if not (hasKey $catalog (toString $tag)) -}}
{{- fail (printf "kerberoshub.workflows.definitions[%q].triggers[%d].systemTags: %q is not in deviceTags.system.catalog; add it to the system tag catalog" $name $i (toString $tag)) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Assemble the deployment-global workflow definitions (WORKFLOW_DEFINITIONS) as a
JSON array from every *enabled* workflow under kerberoshub.workflows.definitions.
This is the engine's boot-loaded configuration source and deployment stage
catalog: several distinct config workflows can run over one recording — each
opens its own run and dispatches only its own stages. Organisation-scoped
database workflows are discovered separately at runtime.
Each enabled definition contributes one workflow object:
id optional explicit stable identity, normalized to lowercase. Omitted
for legacy definitions; their effective id is SHA256(name)[:24].
name the map key (mutable display name when an explicit id is supplied).
enabled always true here (a disabled definition is skipped entirely).
source "config" — provenance marking a Helm-defined, deployment-global,
ops-managed workflow (read-only in the API, no owning organisation).
triggers how a run OPENS. Defaults to a single bare automatic trigger
(opens for every recording); narrow with device/schedule triggers.
Per-stage `needs` (below) decide which stages then FIRE.
stages the executable stage set, each contributing the same routing
descriptor the stageRegistry emits:
operation the stage's operation (unique within the workflow).
dispatch "always" (default) | "conditional".
queue from the matching services.<operation>.queue
(authoritative; omitted when unset so the engine
derives "kcloud-<operation>-queue.fifo").
needs conditional stages only: upstream dependencies, each
{operation?, condition?}, carried through verbatim.
needsMode conditional stages: "any" (default) | "all".
*/}}
{{- define "kerberoshub.workflows.workflowDefinitions" -}}
{{- include "kerberoshub.workflows.validateDefinitions" . -}}
{{- $defs := list -}}
{{- define "kerberoshub.workflows.stageRegistry" -}}
{{- $entries := list -}}
{{- $services := .Values.kerberoshub.services | default dict -}}
{{- range $name, $wf := .Values.kerberoshub.workflows.definitions -}}
{{- if $wf.enabled -}}
{{- $stages := list -}}
{{- range $stage := $wf.stages -}}
{{- $op := $stage.operation -}}
{{- $entry := dict "operation" $op "dispatch" (default "always" $stage.dispatch) -}}
{{- $service := index $services $op -}}
{{- range $name, $stage := .Values.kerberoshub.workflows.stages -}}
{{- if $stage.enabled -}}
{{- $entry := dict "operation" (default $name $stage.operation) "dispatch" (default "always" $stage.dispatch) -}}
{{- $service := index $services $name -}}
{{- if $service }}{{- with $service.queue }}{{- $_ := set $entry "queue" . -}}{{- end }}{{- end }}
{{- with $stage.needs }}{{- $_ := set $entry "needs" . -}}{{- end }}
{{- with $stage.needsMode }}{{- $_ := set $entry "needsMode" . -}}{{- end }}
{{- $stages = append $stages $entry -}}
{{- end -}}
{{- $def := dict "name" $name "enabled" true "source" "config" "triggers" (default (list (dict "type" "automatic")) $wf.triggers) "stages" $stages -}}
{{- if hasKey $wf "id" }}{{- $_ := set $def "id" (lower $wf.id) -}}{{- end }}
{{- $defs = append $defs $def -}}
{{- with $stage.kind }}{{- $_ := set $entry "kind" . -}}{{- end }}
{{- $entries = append $entries $entry -}}
{{- end -}}
{{- end -}}
{{- $defs | toJson -}}
{{- end -}}
{{/*
Expose the deployment's operation→queue catalog to API producers that seed
embedded WorkflowRuns. Unlike WORKFLOW_DEFINITIONS this includes services that
are enabled for internal flows but are absent from user-visible workflow
definitions. The workflows engine remains authoritative for dispatch; producers
use this only to embed the same queue on a synthetic stage.
*/}}
{{- define "kerberoshub.workflows.stageQueues" -}}
{{- $queues := dict -}}
{{- range $operation, $service := (.Values.kerberoshub.services | default dict) -}}
{{- if ne $operation "workflows" -}}
{{- with $service.queue -}}
{{- $_ := set $queues $operation . -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- $queues | toJson -}}
{{- $entries | toJson -}}
{{- end -}}
@@ -1,32 +1,24 @@
{{- /*
Generic workflow-stage worker.
Renders a Deployment + Service for every enabled worker under
kerberoshub.services.<name> other than the `workflows` engine itself. A custom
stage joins the pipeline by values alone — declare its worker here and route to
it from a kerberoshub.workflows.definitions stage of the same operation; no
per-stage template is needed.
Renders a Deployment + Service for every stage under
kerberoshub.workflows.stages that has a matching, enabled worker under
kerberoshub.services.<name>. A custom stage joins the pipeline by values
alone — no per-stage template needed.
Every stage worker receives the same connection contract; the only value that
varies by stage is the consume-queue variable name, <NAME>_QUEUE (a worker
named "loitering" gets LOITERING_QUEUE, "my-stage" gets MY_STAGE_QUEUE). To run
a worker outside the chart instead, leave services.<name>.enabled unset (or
false) and point its workflow stage at the queue you publish.
All stages receive the Vault read credentials (KERBEROS_STORAGE_URI /
ACCESS_KEY / SECRET). A stage that also writes an artefact back to Vault (e.g.
redaction) declares its destination provider with the named field
services.<name>.storageProvider, rendered as KERBEROS_STORAGE_PROVIDER; a
read-only stage omits it and gets no provider env.
Worker-specific settings go in services.<name>.env (plain values) and
services.<name>.secretEnv (references to keys in an existing Secret).
varies by stage is the consume-queue variable name, <NAME>_QUEUE (a stage
keyed "anpr" gets ANPR_QUEUE, "my-stage" gets MY_STAGE_QUEUE). To run a worker
outside the chart instead, leave services.<name>.enabled unset (or false)
while keeping the stage under workflows.stages so the engine still routes to
the queue you publish.
*/ -}}
{{- if and (or (eq .Values.mode "all") (eq .Values.mode "pipeline")) .Values.kerberoshub.workflows.enabled -}}
{{- $root := . -}}
{{- $services := .Values.kerberoshub.services | default dict -}}
{{- range $name, $svc := $services -}}
{{- if and (ne $name "workflows") $svc $svc.enabled -}}
{{- range $name, $stage := .Values.kerberoshub.workflows.stages -}}
{{- $svc := index $services $name -}}
{{- if and $svc $svc.enabled -}}
{{- $queueEnv := printf "%s_QUEUE" ($name | upper | replace "-" "_") -}}
---
apiVersion: apps/v1
@@ -50,10 +42,6 @@ spec:
labels:
app: hub-{{ $name }}
spec:
{{- with $svc.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if $root.Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" $root.Release.Name $root.Chart.Name | trunc 63 | trimSuffix "-") $root.Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -73,10 +61,6 @@ spec:
- name: hub-{{ $name }}
image: "{{ $root.Values.global.imageRegistry }}{{ $svc.repository }}:{{ $svc.tag }}"
imagePullPolicy: {{ $svc.pullPolicy | default "IfNotPresent" }}
{{- with $svc.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with $svc.resources }}
resources:
{{- toYaml . | nindent 12 }}
@@ -118,43 +102,6 @@ spec:
value: "{{ $root.Values.kerberosvault.accesskey }}"
- name: KERBEROS_STORAGE_SECRET
value: "{{ $root.Values.kerberosvault.secretkey }}"
{{- with $svc.storageProvider }}
# Destination Vault provider (KERBEROS_STORAGE_PROVIDER) — only stages
# that write an artefact back (e.g. redaction) set services.<name>.
# storageProvider; read-only stages omit it and get no provider env.
- name: KERBEROS_STORAGE_PROVIDER
value: {{ . | quote }}
{{- end }}
{{- if $root.Values.opentelemetry.enabled }}
# OpenTelemetry tracing: the stage continues the engine's dispatch span
# (the run's traceparent) and follows its sampling decision.
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ $root.Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $root | trim | nindent 8 }}
{{- end }}
# Per-stage tuning knobs. Any key/value under services.<name>.env is
# rendered verbatim as container env, so a worker can be tuned from
# values without a per-stage template. These override the image's own
# ENV defaults; the fixed contract env above is not overridable here.
{{- range $key, $value := $svc.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }} {{- with $svc.secretEnv }}
# Per-stage secret env. Each key under services.<name>.secretEnv maps a
# container env var to a key in an existing Kubernetes Secret
# ({name, key}), so credentials such as a model API key stay out of
# values. The Secret must exist in the release namespace.
{{- range $key, $ref := . }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ required (printf "kerberoshub.services.%s.secretEnv.%s.name is required" $name $key) $ref.name | quote }}
key: {{ required (printf "kerberoshub.services.%s.secretEnv.%s.key is required" $name $key) $ref.key | quote }}
{{- end }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -172,6 +119,6 @@ spec:
protocol: TCP
selector:
app: hub-{{ $name }}
{{ end -}}
{{- end }}
{{- end }}
{{- end }}
@@ -1,4 +1,3 @@
{{- include "kerberoshub.workflows.validateDefinitions" . -}}
{{- if and (or (eq .Values.mode "all") (eq .Values.mode "pipeline")) .Values.kerberoshub.workflows.enabled -}}
apiVersion: apps/v1
kind: Deployment
@@ -19,14 +18,10 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: hub-workflows
spec:
{{- with .Values.kerberoshub.services.workflows.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -34,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberoshub.services.workflows.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberoshub.services.workflows.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberoshub.services.workflows.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -52,48 +41,31 @@ spec:
- name: hub-workflows
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberoshub.services.workflows.repository }}:{{ .Values.kerberoshub.services.workflows.tag }}"
imagePullPolicy: {{ .Values.kerberoshub.services.workflows.pullPolicy }}
{{- with .Values.kerberoshub.services.workflows.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.kerberoshub.services.workflows.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberoshub.services.workflows.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberoshub.services.workflows.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-workflows") | nindent 8 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberoshub.services.workflows.logLevel }}"
- name: QUEUE_SYSTEM
value: "{{ .Values.queueProvider }}"
# Queue this service consumes from (WORKFLOWS_QUEUE) and the set of
# named workflows it runs (WORKFLOW_DEFINITIONS): each with its own
# trigger and executable stages, assembled from the enabled definitions
# under kerberoshub.workflows.definitions (see _workflows-helpers.tpl).
# Definitions are the engine's boot-loaded config source and deployment
# stage catalog. Organisation-scoped database workflows are read per
# recording; an in-cluster engine refuses to start only when both the
# config definitions and the stage-queue catalog below are empty.
# Queue this service consumes from (WORKFLOWS_QUEUE) and the custom
# pipeline stage registry it may dispatch (PIPELINE_STAGE_REGISTRY).
# The registry is assembled from the enabled stages under
# kerberoshub.workflows.stages (see _workflows-helpers.tpl).
- name: WORKFLOWS_QUEUE
value: "{{ .Values.kerberoshub.services.workflows.queue }}"
- name: WORKFLOW_DEFINITIONS
value: {{ include "kerberoshub.workflows.workflowDefinitions" . | quote }}
# Operation→queue catalog so DB workflows reach workers no config workflow references.
- name: WORKFLOW_STAGE_QUEUES
value: {{ include "kerberoshub.workflows.stageQueues" . | quote }}
- name: PIPELINE_STAGE_REGISTRY
value: {{ include "kerberoshub.workflows.stageRegistry" . | quote }}
# RabbitMQ settings
- name: RABBITMQ_HOST
@@ -115,7 +87,6 @@ spec:
- name: KERBEROS_STORAGE_SECRET
value: "{{ .Values.kerberosvault.secretkey }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -123,8 +94,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-analysis
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.analysis.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.analysis.replicas }}
selector:
@@ -22,7 +18,7 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: pipe-analysis
spec:
@@ -33,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberospipeline.analysis.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberospipeline.analysis.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberospipeline.analysis.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -55,20 +45,14 @@ spec:
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberospipeline.analysis.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberospipeline.analysis.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-pipeline-analysis") | nindent 8 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberospipeline.analysis.logLevel }}"
- name: CLOUD_PROVIDER
@@ -103,12 +87,6 @@ spec:
# runs unchanged). Kept in sync with whether the workflows service runs.
- name: WORKFLOWS_ENABLED
value: "{{ .Values.kerberoshub.workflows.enabled }}"
# Queue analysis publishes opened workflow runs to (WORKFLOWS_QUEUE),
# taken from the workflows service's queue so analysis and the engine
# always agree on the queue name (no drift).
- name: WORKFLOWS_QUEUE
value: "{{ .Values.kerberoshub.services.workflows.queue }}"
# Kerberos Vault
- name: KERBEROS_STORAGE_URI
@@ -121,22 +99,7 @@ spec:
# Sprites
- name: SPRITE_ENABLED
value: "{{ .Values.kerberospipeline.sprite.enabled }}"
# Dominant colors
- name: DOMINANTCOLOR_ENABLED
value: "{{ .Values.kerberospipeline.dominantColor.enabled }}"
# Thumbnail regeneration from classified frames (opt-in)
- name: THUMBNAIL_REGENERATION_ENABLED
value: {{ .Values.kerberospipeline.analysis.thumbnailRegeneration.enabled | default false | quote }}
# In-memory cache for hot-path MongoDB lookups
- name: DB_CACHE_ENABLED
value: {{ .Values.kerberospipeline.analysis.dbCache.enabled | default false | quote }}
- name: DB_CACHE_TTL
value: {{ .Values.kerberospipeline.analysis.dbCache.ttl | default "5m" | quote }}
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -144,8 +107,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-counting
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.counting.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.counting.replicas }}
selector:
@@ -24,10 +20,6 @@ spec:
labels:
app: pipe-counting
spec:
{{- with .Values.kerberospipeline.counting.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -47,10 +39,6 @@ spec:
- name: pipe-counting
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberospipeline.counting.repository }}:{{ .Values.kerberospipeline.counting.tag }}"
imagePullPolicy: {{ .Values.kerberospipeline.counting.pullPolicy }}
{{- with .Values.kerberospipeline.counting.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.kerberospipeline.counting.resources }}
resources:
{{- toYaml . | nindent 12 }}
@@ -89,7 +77,6 @@ spec:
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -97,8 +84,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -1,13 +1,9 @@
{{- if and (or (eq .Values.mode "all") (eq .Values.mode "pipeline")) (eq .Values.kerberospipeline.dominantColor.enabled true) -}}
{{- if or (eq .Values.mode "all") (eq .Values.mode "pipeline") -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: pipe-dominantcolor
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.dominantColor.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.dominantColor.replicas }}
selector:
@@ -24,10 +20,6 @@ spec:
labels:
app: pipe-dominantcolor
spec:
{{- with .Values.kerberospipeline.dominantColor.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -47,10 +39,6 @@ spec:
- name: pipe-dominantcolor
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberospipeline.dominantColor.repository }}:{{ .Values.kerberospipeline.dominantColor.tag }}"
imagePullPolicy: {{ .Values.kerberospipeline.dominantColor.pullPolicy }}
{{- with .Values.kerberospipeline.dominantColor.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.kerberospipeline.dominantColor.resources }}
resources:
{{- toYaml . | nindent 12 }}
@@ -89,7 +77,6 @@ spec:
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -97,8 +84,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-event
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.event.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.event.replicas }}
selector:
@@ -22,7 +18,7 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: pipe-event
spec:
@@ -33,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberospipeline.event.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberospipeline.event.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberospipeline.event.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -55,22 +45,16 @@ spec:
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberospipeline.event.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberospipeline.event.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-pipeline-event") | nindent 8 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberospipeline.event.logLevel }}"
- name: READ_ONLY
@@ -102,7 +86,6 @@ spec:
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -110,8 +93,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -18,7 +18,7 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: pipe-export
spec:
@@ -29,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberospipeline.export.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberospipeline.export.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberospipeline.export.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -51,20 +45,14 @@ spec:
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberospipeline.export.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberospipeline.export.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-pipeline-export") | nindent 8 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberospipeline.export.logLevel }}"
{{- if .Values.kerberospipeline.export.playerAssetsPath }}
@@ -134,7 +122,6 @@ spec:
- name: VAULT_THUMBNAIL_SECRET_KEY
value: "{{ .Values.kerberosvault.thumbnail.secretKey }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -142,8 +129,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-monitor
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.monitor.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.monitor.replicas }}
selector:
@@ -22,7 +18,7 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: pipe-monitor
spec:
@@ -33,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberospipeline.monitor.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberospipeline.monitor.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberospipeline.monitor.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -55,24 +45,14 @@ spec:
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberospipeline.monitor.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberospipeline.monitor.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-pipeline-monitor") | nindent 8 }}
# Application
- name: LOG_LEVEL
value: "{{ .Values.kerberospipeline.monitor.logLevel }}"
# Queue
- name: QUEUE_SYSTEM
value: "{{ .Values.queueProvider }}"
@@ -123,7 +103,6 @@ spec:
- name: SMTP_PASSWORD
value: "{{ .Values.email.smtp.password }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -131,8 +110,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -18,7 +18,7 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: pipe-notify-test
spec:
@@ -29,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberospipeline.notifyTest.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberospipeline.notifyTest.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberospipeline.notifyTest.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -51,20 +45,14 @@ spec:
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberospipeline.notifyTest.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberospipeline.notifyTest.volumeMounts}}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-pipeline-notification-test") | nindent 8 }}
- name: QUEUE_SYSTEM
value: "{{ .Values.queueProvider }}"
@@ -122,7 +110,6 @@ spec:
- name: SMTP_PASSWORD
value: "{{ .Values.email.smtp.password }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -130,8 +117,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-notify
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.notify.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.notify.replicas }}
selector:
@@ -22,14 +18,10 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: pipe-notify
spec:
{{- with .Values.kerberospipeline.notify.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -37,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberospipeline.notify.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberospipeline.notify.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberospipeline.notify.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -55,32 +41,20 @@ spec:
- name: pipe-notify
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberospipeline.notify.repository }}:{{ .Values.kerberospipeline.notify.tag }}"
imagePullPolicy: {{ .Values.kerberospipeline.notify.pullPolicy }}
{{- with .Values.kerberospipeline.notify.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.kerberospipeline.notify.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberospipeline.notify.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberospipeline.notify.volumeMounts}}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-pipeline-notification") | nindent 8 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberospipeline.notify.logLevel }}"
- name: NOTIFICATION_EXPIRY_MINUTES
value: "{{ .Values.kerberospipeline.notify.notificationExpiryMinutes }}"
# Queue
- name: QUEUE_SYSTEM
value: "{{ .Values.queueProvider }}"
@@ -106,14 +80,6 @@ spec:
value: "{{ .Values.rabbitmq.username }}"
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
- name: AUDIT_ENABLED
value: {{ and .Values.audit.enabled .Values.kerberospipeline.notify.audit.enabled | quote }}
{{- if and .Values.audit.enabled .Values.kerberospipeline.notify.audit.enabled }}
- name: AUDIT_QUEUE
value: {{ .Values.audit.intake.queue | quote }}
- name: AUDIT_DEADLETTER_QUEUE
value: {{ .Values.audit.intake.deadletterQueue | quote }}
{{- end }}
# Kerberos Vault
- name: STORAGE_URI
@@ -176,7 +142,6 @@ spec:
- name: VAULT_SPRITE_SECRET_KEY
value: "{{ .Values.kerberosvault.sprite.secretKey }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -184,8 +149,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -0,0 +1,114 @@
{{- if or (eq .Values.mode "all") (eq .Values.mode "pipeline") -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: pipe-redaction
namespace: {{ .Release.Namespace }}
spec:
replicas: {{ .Values.kerberospipeline.redaction.replicas }}
selector:
matchLabels:
app: pipe-redaction
minReadySeconds: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
app: pipe-redaction
spec:
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.kerberospipeline.redaction.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.kerberospipeline.redaction.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: pipe-redaction
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberospipeline.redaction.repository }}:{{ .Values.kerberospipeline.redaction.tag }}"
imagePullPolicy: {{ .Values.kerberospipeline.redaction.pullPolicy }}
{{- with .Values.kerberospipeline.redaction.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.kerberospipeline.redaction.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
env:
- name: LOG_LEVEL
value: "{{ .Values.kerberospipeline.redaction.logLevel }}"
- name: CLOUD_PROVIDER
value: "{{ .Values.cloudProvider }}"
- name: QUEUE_SYSTEM
value: "{{ .Values.queueProvider }}"
# Kafka settings
- name: KAFKA_BROKER
value: "{{ .Values.kafka.broker }}"
- name: KAFKA_USERNAME
value: "{{ .Values.kafka.username }}"
- name: KAFKA_PASSWORD
value: "{{ .Values.kafka.password }}"
- name: KAFKA_MECHANISM
value: "{{ .Values.kafka.mechanism }}"
- name: KAFKA_SECURITY
value: "{{ .Values.kafka.security }}"
# RabbitMQ settings
- name: RABBITMQ_HOST
value: "{{ .Values.rabbitmq.host }}"
- name: RABBITMQ_EXCHANGE
value: "{{ .Values.rabbitmq.exchange }}"
- name: RABBITMQ_USERNAME
value: "{{ .Values.rabbitmq.username }}"
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
# Kerberos Vault (used to download the source media and upload the redacted artifact).
- name: KERBEROS_STORAGE_URI
value: "{{ .Values.kerberosvault.uri }}"
- name: KERBEROS_STORAGE_PROVIDER
value: "{{ .Values.kerberosvault.provider }}"
- name: KERBEROS_STORAGE_ACCESS_KEY
value: "{{ .Values.kerberosvault.accesskey }}"
- name: KERBEROS_STORAGE_SECRET
value: "{{ .Values.kerberosvault.secretkey }}"
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
- name: OTEL_EXPORTED_OTLP_ROUTING_ENABLED
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
---
apiVersion: v1
kind: Service
metadata:
name: pipe-redaction
namespace: {{ .Release.Namespace }}
labels:
app: pipe-redaction
service: pipe
spec:
ports:
- name: hub-metrics
port: 8080
targetPort: 8080
protocol: TCP
selector:
app: pipe-redaction
{{- end }}
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-sequence
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.sequence.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.sequence.replicas }}
selector:
@@ -22,7 +18,7 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: pipe-sequence
spec:
@@ -33,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberospipeline.sequence.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberospipeline.sequence.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberospipeline.sequence.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -55,22 +45,14 @@ spec:
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberospipeline.sequence.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberospipeline.sequence.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-pipeline-sequence") | nindent 8 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberospipeline.sequence.logLevel }}"
- name: CLOUD_PROVIDER
value: "{{ .Values.cloudProvider }}"
- name: QUEUE_SYSTEM
@@ -98,7 +80,6 @@ spec:
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -106,8 +87,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-sprite
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.sprite.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.sprite.replicas }}
selector:
@@ -87,10 +83,6 @@ spec:
value: "{{ .Values.rabbitmq.username }}"
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- with .Values.kerberospipeline.sprite.prefetchCount }}
- name: RABBITMQ_PREFETCH_COUNT
value: {{ . | quote }}
{{- end }}
# There is an option to store the sprites in a storage provider in Kerberos Vault.
- name: VAULT_SPRITE_ENABLED
@@ -108,7 +100,6 @@ spec:
- name: VAULT_SPRITE_HEIGHT
value: "{{ .Values.kerberospipeline.sprite.height }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -116,8 +107,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-throttler
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.throttler.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.throttler.replicas }}
selector:
@@ -22,14 +18,10 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: pipe-throttler
spec:
{{- with .Values.kerberospipeline.throttler.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -37,16 +29,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberospipeline.throttler.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberospipeline.throttler.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberospipeline.throttler.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -55,28 +41,18 @@ spec:
- name: pipe-throttler
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberospipeline.throttler.repository }}:{{ .Values.kerberospipeline.throttler.tag }}"
imagePullPolicy: {{ .Values.kerberospipeline.throttler.pullPolicy }}
{{- with .Values.kerberospipeline.throttler.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.kerberospipeline.throttler.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if or .Values.kerberospipeline.throttler.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberospipeline.throttler.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "hub-pipeline-throttler") | nindent 8 }}
- name: LOG_LEVEL
value: "{{ .Values.kerberospipeline.throttler.logLevel }}"
- name: CLOUD_PROVIDER
@@ -106,7 +82,6 @@ spec:
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -114,8 +89,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
kind: Service
@@ -4,10 +4,6 @@ kind: Deployment
metadata:
name: pipe-thumbnail
namespace: {{ .Release.Namespace }}
{{- with .Values.kerberospipeline.thumbnail.deploymentAnnotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.kerberospipeline.thumbnail.replicas }}
selector:
@@ -24,10 +20,6 @@ spec:
labels:
app: pipe-thumbnail
spec:
{{- with .Values.kerberospipeline.thumbnail.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.kerberoshub.serviceAccount.create }}
serviceAccountName: {{ default (printf "%s-%s-sa" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-") .Values.kerberoshub.serviceAccount.name }}
{{- end }}
@@ -47,10 +39,6 @@ spec:
- name: pipe-thumbnail
image: "{{ .Values.global.imageRegistry }}{{ .Values.kerberospipeline.thumbnail.repository }}:{{ .Values.kerberospipeline.thumbnail.tag }}"
imagePullPolicy: {{ .Values.kerberospipeline.thumbnail.pullPolicy }}
{{- with .Values.kerberospipeline.thumbnail.securityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.kerberospipeline.thumbnail.resources }}
resources:
{{- toYaml . | nindent 12 }}
@@ -95,10 +83,6 @@ spec:
value: "{{ .Values.rabbitmq.username }}"
- name: RABBITMQ_PASSWORD
value: "{{ .Values.rabbitmq.password }}"
{{- with .Values.kerberospipeline.thumbnail.prefetchCount }}
- name: RABBITMQ_PREFETCH_COUNT
value: {{ . | quote }}
{{- end }}
# Thumbnail generation
- name: THUMBNAIL_QUALITY
@@ -107,8 +91,6 @@ spec:
value: "{{ .Values.kerberospipeline.thumbnail.width }}"
- name: THUMBNAIL_HEIGHT
value: "{{ .Values.kerberospipeline.thumbnail.height }}"
- name: THUMBNAIL_SKIP_NON_KEYFRAMES
value: "{{ .Values.kerberospipeline.thumbnail.skipNonKeyframes }}"
# There is an option to store the thumbnails in a storage provider in Kerberos Vault.
# This will lower storage in mongodb.
@@ -121,7 +103,6 @@ spec:
- name: VAULT_THUMBNAIL_SECRET_KEY
value: "{{ .Values.kerberosvault.thumbnail.secretKey }}"
{{- if .Values.opentelemetry.enabled }}
# Open Telemetry tracing
- name: OTEL_EXPORTED_OTLP_ENABLED
value: "{{ .Values.opentelemetry.enabled }}"
@@ -129,8 +110,6 @@ spec:
value: "{{ .Values.opentelemetry.routingEnabled }}"
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "{{ .Values.opentelemetry.collector.endpoint }}"
{{- include "hub.opentelemetry.samplerEnv" $ | trim | nindent 8 }}
{{- end }}
---
apiVersion: v1
@@ -19,7 +19,7 @@ spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configMaps/configmap-mongodb.yaml") . | sha256sum }}
checksum/config: {{ include (print $.Template.BasePath "/configmap-mongodb.yaml") . | sha256sum }}
labels:
app: vault-forwarder
spec:
@@ -27,16 +27,10 @@ spec:
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- $mongodbTLS := .Values.mongodb.tls }}
{{- if or .Values.kerberoshub.forwarder.volumes (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumes:
{{- with .Values.kerberoshub.forwarder.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolume" . | nindent 8 }}
{{- end }}
{{- end }}
{{- with .Values.kerberoshub.forwarder.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
@@ -49,20 +43,14 @@ spec:
requests:
memory: 10Mi
cpu: 10m
{{- if or .Values.kerberoshub.forwarder.volumeMounts (and $mongodbTLS.enabled $mongodbTLS.existingSecret) }}
volumeMounts:
{{- with .Values.kerberoshub.forwarder.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if and $mongodbTLS.enabled $mongodbTLS.existingSecret }}
{{- include "hub.mongodb.tlsVolumeMount" . | nindent 12 }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
name: mongodb-config
env:
{{- include "hub.mongodb.appUriEnv" (dict "root" $ "app" "vault-forwarder") | nindent 10 }}
- name: ITERATION_SPEED
value: "5"
- name: BUFFER_TIME
@@ -1,4 +1,4 @@
{{- if and (eq .Values.mode "all") .Values.kerberoshub.proxy.enabled -}}
{{- if eq .Values.mode "all" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
-178
View File
@@ -1,178 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"classificationCatalogExistingConfigMap": {
"type": "string",
"maxLength": 253,
"pattern": "^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"
},
"classificationCatalog": {
"type": ["array", "null"],
"minItems": 1,
"description": "Optional inline classification catalog in the Hub shared choice catalog format; replaces the bundled defaults in the chart's classification-catalog ConfigMap. Omit (or null) for the bundled defaults. Keys must be unique (checked when rendering).",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["key", "label"],
"properties": {
"key": {"type": "string", "minLength": 1},
"label": {"type": "string", "minLength": 1},
"icon": {"type": "string", "minLength": 1}
}
}
},
"deviceTags": {
"type": "object",
"additionalProperties": false,
"properties": {
"system": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean",
"description": "Owners may assign system tags and global workflows may select devices by them. Only for deployments whose owners are trusted (self-hosted)."
},
"catalog": {
"type": "array",
"description": "The system tags owners can assign, in the Hub shared choice catalog format (key, label) plus an optional description. Keys must be unique (checked when rendering).",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["key", "label"],
"properties": {
"key": {
"type": "string",
"maxLength": 64,
"pattern": "^[a-z0-9]([a-z0-9._:-]*[a-z0-9])?$"
},
"label": {"type": "string", "minLength": 1},
"description": {"type": "string"}
}
}
}
}
}
}
},
"kerberoshub": {
"type": "object",
"properties": {
"api": {
"type": "object",
"properties": {
"passkeys": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": {"type": "boolean"},
"rpId": {
"type": "string",
"description": "Stable WebAuthn relying-party hostname, without scheme, port or path. Must match each frontend origin's hostname or be its parent domain."
},
"origins": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string",
"pattern": "^https://[^/?#]+$|^http://localhost(:[0-9]+)?$"
},
"description": "Exact trusted frontend origins, with no path or trailing slash. HTTPS is required except for HTTP localhost development."
},
"rpName": {"type": "string"}
},
"if": {
"required": ["enabled"],
"properties": {"enabled": {"const": true}}
},
"then": {
"required": ["rpId", "origins"],
"properties": {
"rpId": {"minLength": 1},
"origins": {"minItems": 1}
}
}
},
"corsAllowedOrigins": {
"type": "array",
"items": {
"type": "string",
"pattern": "^https?://[^/?#]+$"
}
}
}
}
}
},
"workflowConfiguration": {
"type": "object",
"additionalProperties": false,
"required": ["enabled"],
"not": {
"allOf": [
{"anyOf": [{"required": ["includeDefaults"]}, {"required": ["configMaps"]}]},
{"anyOf": [{"required": ["existingConfigMap"]}, {"required": ["items"]}, {"required": ["extraConfigMaps"]}]}
]
},
"properties": {
"enabled": {"type": "boolean"},
"includeDefaults": {
"type": "boolean",
"description": "Include bundled files not explicitly replaced by configMaps items; true when omitted."
},
"configMaps": {
"type": "array",
"items": {"$ref": "#/definitions/configMapSource"},
"description": "Add files or explicitly replace a bundled file using replace: true on an item."
},
"extraConfigMaps": {
"type": "array",
"description": "Legacy additive sources; use configMaps for new deployments.",
"items": {"$ref": "#/definitions/configMapSource"}
},
"existingConfigMap": {
"type": "string",
"maxLength": 253,
"pattern": "^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"
},
"items": {
"type": "array",
"items": {"$ref": "#/definitions/configMapItem"}
}
}
}
},
"definitions": {
"configMapSource": {
"type": "object",
"additionalProperties": false,
"required": ["name", "items"],
"properties": {
"name": {
"type": "string",
"maxLength": 253,
"pattern": "^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"
},
"items": {
"type": "array",
"minItems": 1,
"items": {"$ref": "#/definitions/configMapItem"}
}
}
},
"configMapItem": {
"type": "object",
"additionalProperties": false,
"required": ["key", "path"],
"properties": {
"key": {"type": "string", "pattern": "^[A-Za-z0-9._-]+$"},
"path": {"type": "string", "pattern": "^(workflow-contracts|catalogs)/[A-Za-z0-9_-][A-Za-z0-9._-]*\\.(yaml|json)$"},
"replace": {
"type": "boolean",
"description": "Replace this whole bundled file, not individual fields/entries. Requires configMaps and includeDefaults: true; the path must identify a bundled file."
}
}
}
}
}
+150 -538
View File
File diff suppressed because it is too large Load Diff
-82
View File
@@ -1,82 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
CHART_DIR="${1:-charts/hub}"
resource() {
local source="$1"
awk -v source="# Source: hub/templates/admin/$source.yaml" '
/^---/ { selected=0 }
/^# Source:/ { selected=($0 == source); next }
selected { print }
'
}
assert_contains() {
local rendered="$1" pattern="$2"
if ! grep -Eq -- "$pattern" <<< "$rendered"; then
printf 'Missing expected Admin setting: %s\n' "$pattern" >&2
return 1
fi
}
assert_absent() {
local rendered="$1" pattern="$2"
if grep -Eq -- "$pattern" <<< "$rendered"; then
printf 'Unexpected Admin setting: %s\n' "$pattern" >&2
return 1
fi
}
HARDENED_FLAGS=(
--set admin.containerPort=8080
--set-json 'admin.securityContext={"runAsNonRoot":true,"runAsUser":65532,"runAsGroup":65532,"readOnlyRootFilesystem":true,"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"seccompProfile":{"type":"RuntimeDefault"}}'
--set-json 'admin.volumes=[{"name":"admin-tmp","emptyDir":{"medium":"Memory","sizeLimit":"16Mi"}}]'
--set-json 'admin.volumeMounts=[{"name":"admin-tmp","mountPath":"/tmp"}]'
--set-json 'admin.readinessProbe={"httpGet":{"path":"/healthz","port":"http"},"periodSeconds":10}'
--set-json 'admin.livenessProbe={"httpGet":{"path":"/healthz","port":"http"},"initialDelaySeconds":10,"periodSeconds":10}'
)
for mode in all ui; do
default_render="$(helm template hub "$CHART_DIR" --set "mode=$mode" --set admin.oauth2Proxy.enabled=true)"
default_deployment="$(resource deployment <<< "$default_render")"
default_service="$(resource service <<< "$default_render")"
default_ingress="$(resource ingress <<< "$default_render")"
default_oauth="$(resource oauth2-proxy <<< "$default_render")"
assert_contains "$default_deployment" 'containerPort: 80$'
assert_absent "$default_deployment" 'securityContext:|readinessProbe:|livenessProbe:'
assert_contains "$default_service" 'port: 80$'
assert_contains "$default_service" 'targetPort: http$'
hardened_render="$(helm template hub "$CHART_DIR" --set "mode=$mode" --set admin.oauth2Proxy.enabled=true "${HARDENED_FLAGS[@]}")"
hardened_deployment="$(resource deployment <<< "$hardened_render")"
assert_contains "$hardened_deployment" 'containerPort: 8080$'
assert_absent "$hardened_deployment" 'containerPort: 80$'
for setting in 'runAsNonRoot: true' 'runAsUser: 65532' 'runAsGroup: 65532' \
'readOnlyRootFilesystem: true' 'allowPrivilegeEscalation: false' \
'type: RuntimeDefault' 'drop:' '- ALL' 'medium: Memory' \
'sizeLimit: 16Mi' 'mountPath: /tmp' 'name: admin-tmp'; do
assert_contains "$hardened_deployment" "^[[:space:]]*(- )?$setting$"
done
for probe in readinessProbe livenessProbe; do
probe_render="$(awk -v probe="$probe:" '
/^ [a-zA-Z]/ { selected=($1 == probe) }
selected { print }
' <<< "$hardened_deployment")"
assert_contains "$probe_render" 'path: /healthz$'
assert_contains "$probe_render" 'port: http$'
done
[[ "$(resource service <<< "$hardened_render")" == "$default_service" ]]
[[ "$(resource ingress <<< "$hardened_render")" == "$default_ingress" ]]
[[ "$(resource oauth2-proxy <<< "$hardened_render")" == "$default_oauth" ]]
assert_contains "$default_ingress" 'nginx.ingress.kubernetes.io/auth-url:'
assert_contains "$default_ingress" 'number: 80$'
echo "OK ($mode): legacy defaults; hardened runtime/probes; stable Service, ingress and OAuth2"
done
pipeline_render="$(helm template hub "$CHART_DIR" --set mode=pipeline "${HARDENED_FLAGS[@]}")"
assert_absent "$pipeline_render" '^# Source: hub/templates/admin/'
echo "All Admin runtime checks passed."
-185
View File
@@ -1,185 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
CHART_DIR="${1:-charts/hub}"
components=(
kerberospipeline.counting kerberospipeline.throttler
kerberospipeline.notify
kerberospipeline.thumbnail kerberospipeline.dominantColor
kerberoshub.cleanup kerberoshub.monitordevice
kerberoshub.services.workflows kerberoshub.services.loitering
)
fixtures=(
--set kerberospipeline.dominantColor.enabled=true
--set kerberoshub.workflows.enabled=true
--set kerberoshub.services.loitering.enabled=true
--set kerberoshub.services.loitering.repository=example/loitering
--set kerberoshub.services.loitering.tag=test
--set kerberoshub.services.loitering.queue=loitering
--set mongodb.tls.enabled=true
--set mongodb.tls.existingSecret=mongodb-ca
--set mongodb.tls.caFileName=ca.crt
)
security=()
for component in "${components[@]}"; do
security+=(
--set "$component.securityContext.runAsNonRoot=true"
--set "$component.securityContext.runAsUser=65532"
--set "$component.securityContext.runAsGroup=65532"
--set "$component.securityContext.readOnlyRootFilesystem=true"
--set "$component.securityContext.allowPrivilegeEscalation=false"
--set "$component.securityContext.capabilities.drop[0]=ALL"
--set "$component.securityContext.seccompProfile.type=RuntimeDefault"
--set "$component.podSecurityContext.fsGroup=65532"
--set "$component.volumes[0].name=scratch"
--set "$component.volumes[0].emptyDir.sizeLimit=4Gi"
--set "$component.volumeMounts[0].name=scratch"
--set "$component.volumeMounts[0].mountPath=/tmp"
--set "$component.resources.requests.ephemeral-storage=4Gi"
--set "$component.resources.limits.ephemeral-storage=6Gi"
)
done
resource() {
local kind="$1" name="$2"
awk -v kind="$kind" -v name="$name" '
function emit() { if (matchedKind && matchedName) printf "%s", block }
/^---$/ { emit(); block=""; matchedKind=0; matchedName=0 }
{ block=block $0 "\n" }
$0 == "kind: " kind { matchedKind=1 }
$0 == " name: " name { matchedName=1 }
END { emit() }
'
}
assert_line() {
local block="$1" pattern="$2"
if ! grep -Eq "$pattern" <<< "$block"; then
printf 'Missing expected pattern: %s\n%s\n' "$pattern" "$block" >&2
exit 1
fi
}
for mode in all pipeline ui; do
defaults="$(helm template hub "$CHART_DIR" --set "mode=$mode")"
if grep -q 'securityContext:' <<< "$defaults"; then
echo "Default $mode mode unexpectedly enables security settings" >&2
exit 1
fi
legacy="$(helm template hub "$CHART_DIR" --set "mode=$mode" "${fixtures[@]}")"
hardened="$(helm template hub "$CHART_DIR" --set "mode=$mode" "${fixtures[@]}" "${security[@]}")"
helm lint "$CHART_DIR" --quiet --set "mode=$mode" "${fixtures[@]}" "${security[@]}"
names=()
if [[ "$mode" != ui ]]; then
names+=(pipe-counting pipe-throttler pipe-notify pipe-thumbnail pipe-dominantcolor hub-workflows hub-loitering)
fi
if [[ "$mode" != pipeline ]]; then
names+=(hub-cleanup hub-monitor-device)
fi
for name in "${names[@]}"; do
block="$(resource Deployment "$name" <<< "$hardened")"
for pattern in \
'^[ ]{6}securityContext:$' '^[ ]{8}fsGroup: 65532$' \
'^[ ]+(runAsUser|runAsGroup): 65532$' \
'^[ ]+runAsNonRoot: true$' '^[ ]+readOnlyRootFilesystem: true$' \
'^[ ]+allowPrivilegeEscalation: false$' '^[ ]+capabilities:$' \
'^[ ]+drop:$' '^[ ]+- ALL$' '^[ ]+seccompProfile:$' \
'^[ ]+type: RuntimeDefault$' '^[ ]+(- )?mountPath: /tmp$' \
'^[ ]+sizeLimit: 4Gi$' '^[ ]+ephemeral-storage: 6Gi$' \
'^[ ]+ephemeral-storage: 4Gi$'; do
assert_line "$block" "$pattern"
done
# Verify both identity axes independently.
assert_line "$block" '^[ ]+runAsUser: 65532$'
assert_line "$block" '^[ ]+runAsGroup: 65532$'
assert_line "$block" '^[ ]{8,10}securityContext:$'
if [[ "$name" == hub-cleanup || "$name" == hub-monitor-device || "$name" == hub-workflows || "$name" == pipe-notify ]]; then
assert_line "$block" '^[ ]+secretName: mongodb-ca$'
assert_line "$block" '^[ ]+mountPath: /etc/mongodb/tls$'
assert_line "$block" '^[ ]+readOnly: true$'
fi
if [[ "$name" == pipe-notify ]]; then
# Provider, queue, FFmpeg and all other worker settings are unchanged.
old_block="$(resource Deployment pipe-notify <<< "$legacy")"
[[ "$(sed -n '/^ env:/,$p' <<< "$old_block")" == "$(sed -n '/^ env:/,$p' <<< "$block")" ]]
fi
if [[ "$name" != hub-monitor-device ]]; then
service="$(resource Service "$name" <<< "$hardened")"
assert_line "$service" '^[ ]+port: 8080$'
assert_line "$service" '^[ ]+targetPort: 8080$'
fi
done
expected="${#names[@]}"
[[ "$(grep -c 'runAsUser: 65532' <<< "$hardened")" == "$expected" ]]
[[ "$(grep -c 'fsGroup: 65532' <<< "$hardened")" == "$expected" ]]
# Image selection, Services, env and TLS mounts must not change.
for pattern in '^[ ]+image:' '^[ ]+(port|targetPort|containerPort):' 'mongodb-tls'; do
[[ "$(grep -E "$pattern" <<< "$legacy")" == "$(grep -E "$pattern" <<< "$hardened")" ]]
done
echo "OK ($mode): defaults unchanged; $expected independent hardened workers preserve images, ports and MongoDB TLS"
done
# Hardening one worker must not opt in another, even on the same pod mode.
isolated="$(helm template hub "$CHART_DIR" --set mode=pipeline \
--set kerberospipeline.counting.securityContext.runAsUser=65532)"
[[ "$(grep -c 'runAsUser: 65532' <<< "$isolated")" == 1 ]]
assert_line "$(resource Deployment pipe-counting <<< "$isolated")" '^[ ]+runAsUser: 65532$'
echo "All hardened worker checks passed."
admin_flags=(
--set admin.containerPort=8080
--set admin.securityContext.runAsNonRoot=true
--set admin.securityContext.runAsUser=65532
--set admin.securityContext.runAsGroup=65532
--set admin.securityContext.readOnlyRootFilesystem=true
--set admin.securityContext.allowPrivilegeEscalation=false
--set admin.securityContext.capabilities.drop[0]=ALL
--set admin.securityContext.seccompProfile.type=RuntimeDefault
--set admin.volumes[0].name=admin-tmp
--set admin.volumes[0].emptyDir.medium=Memory
--set admin.volumes[0].emptyDir.sizeLimit=16Mi
--set admin.volumeMounts[0].name=admin-tmp
--set admin.volumeMounts[0].mountPath=/tmp
--set admin.oauth2Proxy.enabled=true
)
for mode in all ui pipeline; do
legacy="$(helm template hub "$CHART_DIR" --set "mode=$mode" --set admin.oauth2Proxy.enabled=true)"
configured="$(helm template hub "$CHART_DIR" --set "mode=$mode" "${admin_flags[@]}")"
helm lint "$CHART_DIR" --quiet --set "mode=$mode" "${admin_flags[@]}"
if [[ "$mode" == pipeline ]]; then
[[ -z "$(resource Deployment admin <<< "$configured")" ]]
[[ -z "$(resource Service admin-svc <<< "$configured")" ]]
[[ "$legacy" == "$configured" ]]
echo "OK (pipeline): Admin settings render no Admin resources or unrelated changes"
continue
fi
old="$(resource Deployment admin <<< "$legacy")"
block="$(resource Deployment admin <<< "$configured")"
assert_line "$old" '^[ ]+containerPort: 80$'
[[ "$old" != *securityContext:* && "$old" != *admin-tmp* ]]
for pattern in \
'^[ ]+containerPort: 8080$' '^[ ]{10}securityContext:$' \
'^[ ]+runAsUser: 65532$' '^[ ]+runAsGroup: 65532$' \
'^[ ]+runAsNonRoot: true$' '^[ ]+readOnlyRootFilesystem: true$' \
'^[ ]+allowPrivilegeEscalation: false$' '^[ ]+capabilities:$' \
'^[ ]+drop:$' '^[ ]+- ALL$' '^[ ]+seccompProfile:$' \
'^[ ]+type: RuntimeDefault$' '^[ ]+medium: Memory$' \
'^[ ]+sizeLimit: 16Mi$' '^[ ]+(- )?mountPath: /tmp$'; do
assert_line "$block" "$pattern"
done
old_service="$(resource Service admin-svc <<< "$legacy")"
service="$(resource Service admin-svc <<< "$configured")"
assert_line "$old_service" '^[ ]+targetPort: http$'
assert_line "$service" '^[ ]+port: 80$'
assert_line "$service" '^[ ]+targetPort: http$'
[[ "$(resource Ingress admin-ingress <<< "$legacy")" == "$(resource Ingress admin-ingress <<< "$configured")" ]]
[[ "$(resource Deployment oauth2-proxy-admin <<< "$legacy")" == "$(resource Deployment oauth2-proxy-admin <<< "$configured")" ]]
[[ "$(resource Service oauth2-proxy-admin <<< "$legacy")" == "$(resource Service oauth2-proxy-admin <<< "$configured")" ]]
[[ "$(grep 'image:' <<< "$legacy")" == "$(grep 'image:' <<< "$configured")" ]]
# No other workload inherits Admin's container port or security settings.
[[ "$(grep -c 'runAsUser: 65532' <<< "$configured")" == 1 ]]
echo "OK ($mode): Admin opt-in port/security/tmpfs; legacy image, Service port, ingress and OAuth2-proxy preserved"
done
echo "All hardened Admin checks passed."
-98
View File
@@ -1,98 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
CHART_DIR="${1:-charts/hub}"
extract_passkeys() {
awk '
/^---/ { deployment=0; name=""; variable="" }
/^kind: Deployment$/ { deployment=1 }
deployment && /^ name:/ { name=$2 }
deployment && /- name: PASSKEY_/ { variable=$3; next }
variable != "" && /value:/ {
value=$0
sub(/^[[:space:]]*value: /, "", value)
print name, variable, value
variable=""
}
' | sort
}
assert_passkeys() {
local rendered="$1" expected="$2" actual count expected_count
actual="$(printf '%s\n' "$rendered" | extract_passkeys)"
if [[ "$actual" != "$expected" ]]; then
printf 'Unexpected passkey environment:\n%s\nExpected:\n%s\n' "$actual" "$expected" >&2
return 1
fi
count="$(printf '%s\n' "$rendered" | awk '/- name: PASSKEY_/ { count++ } END { print count+0 }')"
expected_count="$(printf '%s\n' "$expected" | awk 'NF { count++ } END { print count+0 }')"
if [[ "$count" != "$expected_count" ]]; then
echo "Passkey variables leaked outside the expected Deployment or were duplicated" >&2
return 1
fi
}
CONFIGURED_FLAGS=(
--set-json kerberoshub.api.passkeys.enabled=true
--set-json 'kerberoshub.api.passkeys.rpId="example.com"'
--set-json 'kerberoshub.api.passkeys.origins=["https://hub.example.com","https://legacy.example.com:8443"]'
--set-json 'kerberoshub.api.passkeys.rpName="Example Hub"'
)
expected="$(printf '%s\n' \
'hub-api PASSKEY_ORIGINS "https://hub.example.com,https://legacy.example.com:8443"' \
'hub-api PASSKEY_RP_ID "example.com"' \
'hub-api PASSKEY_RP_NAME "Example Hub"' | sort)"
for mode in all ui pipeline; do
default_render="$(helm template hub "$CHART_DIR" --set "mode=$mode")"
assert_passkeys "$default_render" ""
configured_render="$(helm template hub "$CHART_DIR" --set "mode=$mode" "${CONFIGURED_FLAGS[@]}")"
if [[ "$mode" == pipeline ]]; then
assert_passkeys "$configured_render" ""
else
assert_passkeys "$configured_render" "$expected"
fi
echo "OK ($mode): defaults opt out; enabled settings affect Hub API only"
done
disabled_render="$(helm template hub "$CHART_DIR" "${CONFIGURED_FLAGS[@]}" --set kerberoshub.api.passkeys.enabled=false)"
assert_passkeys "$disabled_render" ""
localhost_render="$(helm template hub "$CHART_DIR" --set mode=ui \
--set kerberoshub.api.passkeys.enabled=true \
--set-string kerberoshub.api.passkeys.rpId=localhost \
--set-json 'kerberoshub.api.passkeys.origins=["http://localhost:4200"]')"
assert_passkeys "$localhost_render" "$(printf '%s\n' \
'hub-api PASSKEY_ORIGINS "http://localhost:4200"' \
'hub-api PASSKEY_RP_ID "localhost"' \
'hub-api PASSKEY_RP_NAME "Kerberos Hub"' | sort)"
legacy_render="$(helm template hub "$CHART_DIR" --set mode=ui \
--set-json 'kerberoshub.extraEnv=[{"name":"PASSKEY_RP_ID","value":"example.com"}]')"
printf '%s\n' "$legacy_render" | grep -q -- '- name: PASSKEY_RP_ID'
expect_invalid() {
local output
if output="$(helm template hub "$CHART_DIR" "${CONFIGURED_FLAGS[@]}" "$@" 2>&1)"; then
echo "Invalid passkey settings unexpectedly rendered: $*" >&2
return 1
fi
if [[ "$output" != *"passkeys"* ]]; then
printf 'Rendering failed for an unexpected reason:\n%s\n' "$output" >&2
return 1
fi
}
expect_invalid --set-string kerberoshub.api.passkeys.rpId=
expect_invalid --set-json 'kerberoshub.api.passkeys.origins=[]'
expect_invalid --set-json 'kerberoshub.api.passkeys.origins=["https://hub.example.com/"]'
expect_invalid --set-json 'kerberoshub.api.passkeys.origins=["http://hub.example.com"]'
expect_invalid --set-json 'kerberoshub.api.passkeys.origins=["https://hub.example.com","https://hub.example.com"]'
expect_invalid --set-json 'kerberoshub.api.passkeys.origins="https://hub.example.com"'
expect_invalid --set-json 'kerberoshub.api.passkeys.enabled="true"'
expect_invalid --set-json 'kerberoshub.api.passkeys.rpId=123'
expect_invalid --set-json 'kerberoshub.api.passkeys.rpName=123'
expect_invalid --set-string kerberoshub.api.passkeys.origin=https://hub.example.com
echo "All Hub passkey configuration checks passed."
@@ -1,81 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
CHART_DIR="${1:-charts/hub}"
# Supply per-service test overrides without requiring a separate values file.
WAVE_FLAGS=()
for setting in event:10 notify:20 throttler:30 analysis:40 thumbnail:50 sprite:50 dominantColor:50 counting:50 sequence:60 monitor:70; do
service="${setting%%:*}"
wave="${setting#*:}"
WAVE_FLAGS+=(--set-string "kerberospipeline.${service}.deploymentAnnotations.argocd\\.argoproj\\.io/sync-wave=${wave}")
done
# Only read Deployment metadata, never pod-template or Service annotations.
extract_waves() {
awk '
/^---/ { deployment=0; metadata=0; name="" }
/^kind: Deployment$/ { deployment=1 }
/^metadata:$/ { metadata=1; next }
/^[^ #]/ { metadata=0 }
deployment && metadata && /^ name:/ { name=$2 }
deployment && metadata && /^ argocd.argoproj.io\/sync-wave:/ {
value=$2
gsub(/"/, "", value)
print name, value
}
' | sort
}
assert_waves() {
local rendered="$1"
local expected="$2"
local actual
actual="$(printf '%s\n' "$rendered" | extract_waves)"
if [[ "$actual" != "$expected" ]]; then
printf 'Unexpected Deployment waves:\n%s\nExpected:\n%s\n' "$actual" "$expected" >&2
return 1
fi
local all_count expected_count
all_count="$(printf '%s\n' "$rendered" | grep -c 'argocd.argoproj.io/sync-wave:' || true)"
expected_count="$(printf '%s\n' "$expected" | awk 'NF { count++ } END { print count+0 }')"
if [[ "$all_count" != "$expected_count" ]]; then
echo "Sync-wave annotation leaked outside expected Deployment metadata" >&2
return 1
fi
}
expected="$(printf '%s\n' \
'pipe-event 10' 'pipe-notify 20' 'pipe-throttler 30' 'pipe-analysis 40' \
'pipe-thumbnail 50' 'pipe-sprite 50' 'pipe-dominantcolor 50' \
'pipe-counting 50' 'pipe-sequence 60' 'pipe-monitor 70' | sort)"
for mode in all pipeline; do
default_render="$(helm template hub "$CHART_DIR" --set "mode=$mode" --set kerberospipeline.sprite.enabled=true --set kerberospipeline.dominantColor.enabled=true)"
assert_waves "$default_render" ""
if printf '%s\n' "$default_render" | grep -q '^ annotations: null'; then
echo "Empty annotations must be omitted" >&2
exit 1
fi
configured_render="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set "mode=$mode" --set kerberospipeline.sprite.enabled=true --set kerberospipeline.dominantColor.enabled=true)"
assert_waves "$configured_render" "$expected"
echo "OK ($mode): defaults opt out; per-service values assign all ten Deployment waves"
done
disabled_optional="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set mode=pipeline)"
assert_waves "$disabled_optional" "$(printf '%s\n' "$expected" | grep -v -e '^pipe-sprite ' -e '^pipe-dominantcolor ')"
ui_render="$(helm template hub "$CHART_DIR" "${WAVE_FLAGS[@]}" --set mode=ui --set kerberospipeline.sprite.enabled=true --set kerberospipeline.dominantColor.enabled=true)"
assert_waves "$ui_render" ""
# Exercise zero/negative strings and an unrelated annotation on the same map.
for wave in 0 -10; do
override="$(helm template hub "$CHART_DIR" --set mode=pipeline \
--set-string "kerberospipeline.event.deploymentAnnotations.argocd\\.argoproj\\.io/sync-wave=$wave" \
--set-string 'kerberospipeline.event.deploymentAnnotations.example\.com/owner=queue-team')"
assert_waves "$override" "pipe-event $wave"
printf '%s\n' "$override" | grep -q "^ argocd.argoproj.io/sync-wave: \"$wave\"$"
printf '%s\n' "$override" | grep -q '^ example.com/owner: queue-team$'
done
echo "All pipeline Deployment annotation checks passed."