Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
3195c2a
chore
MichaelThamm May 8, 2026
df9c6b8
chore
MichaelThamm May 8, 2026
9c85e89
feat: Sigma rules pt.2
MichaelThamm May 8, 2026
4ac40cb
chore
MichaelThamm May 8, 2026
6718670
chore
MichaelThamm May 8, 2026
555c567
Merge branch 'feat/sigma-rules' into feat/sigma-rules-2
MichaelThamm May 8, 2026
c03c530
chore
MichaelThamm May 8, 2026
ab0642b
chore
MichaelThamm Jun 25, 2026
f270abd
feat(otlp): sort keys when serializing rules to databag for determini…
MichaelThamm Jun 26, 2026
5d414b8
merge: pull otlp rules serializer sort from feat/sigma-rules
MichaelThamm Jun 26, 2026
17a8bbd
chore
MichaelThamm Jun 26, 2026
f07f418
docs: replace the PGP key with the upstream page in SECURITY.md (#468)
tromai May 11, 2026
edcde2e
docs: remove broken link (#471)
james-garner-canonical May 14, 2026
55c68d0
chore(deps): bump urllib3 from 2.6.3 to 2.7.0 in /interfaces/otlp (#469)
dependabot[bot] May 15, 2026
a71b682
docs(rollingops): improve docs for base_dir parameter (#470)
patriciareinoso May 15, 2026
58ae1d0
chore(deps): bump cryptography from 46.0.5 to 46.0.7 in /interfaces/t…
dependabot[bot] May 15, 2026
89dd0d1
feat(rollingops): waiting condition in other units (#475)
sinclert-canonical May 21, 2026
815ac95
ci: upload charmcraft logs (#456)
james-garner-canonical May 21, 2026
9be5bee
ci: use a more recent version of actions/upload-artifact (#484)
james-garner-canonical May 22, 2026
d352b80
docs: fix schema links (#473)
james-garner-canonical May 24, 2026
ecea9d5
docs: add pathops/CONTRIBUTING.md (#490)
james-garner-canonical May 25, 2026
99bfd7e
docs: expand README.md, revamp CONTRIBUTING.md, add AGENTS.md (#489)
james-garner-canonical May 25, 2026
6b92066
docs: charmcraft fetch-libs deprecation (#491)
james-garner-canonical May 26, 2026
86f8b61
docs: include RHS TOCs in custom build process (#495)
james-garner-canonical May 26, 2026
4ddd3ca
test(pathops): fix functional test breakage when running locally (#488)
james-garner-canonical May 27, 2026
72f63da
fix(rollingops): dynamic cluster id integration with etcd and sync lo…
patriciareinoso May 27, 2026
c591c35
chore: add 7-day Dependabot cooldown to version updates (#499)
tonyandrewmeyer May 28, 2026
030327c
test: add workshop support to make functional tests easier to run loc…
james-garner-canonical May 28, 2026
1e0192c
chore: use SPDX license expression in maintainer-owned pyproject.toml…
tonyandrewmeyer Jun 2, 2026
3836ff8
docs: update lib metadata (#509)
james-garner-canonical Jun 2, 2026
7d55178
ci: replace library csvs with yaml (#510)
james-garner-canonical Jun 2, 2026
e288f54
feat: support `str | os.PathLike` in `PathProtocol.glob` and `LocalPa…
tonyandrewmeyer Jun 2, 2026
6385bf3
docs: populate lib fields for identity interfaces (#506)
james-garner-canonical Jun 2, 2026
36eec01
feat: library tags (#513)
james-garner-canonical Jun 3, 2026
37fb8ad
docs: fix typo in readme (#514)
james-garner-canonical Jun 3, 2026
52a55e7
feat: Cache private key in TLS library (#511)
swetha1654 Jun 3, 2026
c8fad75
docs: drop block quotes for links (#493)
james-garner-canonical Jun 5, 2026
0c3bef1
docs: diataxis package docs (#504)
james-garner-canonical Jun 5, 2026
9342c9c
fix: add modelerror check when loading relation data (#411)
kayra1 Jun 5, 2026
ff91bb3
docs: sphinx pack migration (#517)
james-garner-canonical Jun 14, 2026
ab459a4
ci: thin justfile (#518)
james-garner-canonical Jun 15, 2026
ad7ce57
feat(istio-metadata): adds the istio-metadata library (#522)
adhityaravi Jun 15, 2026
6770499
docs: update project URLs for Charm Tech libs and release (#528)
james-garner-canonical Jun 16, 2026
a3436ab
ci: also export library docs URLs for interfaces (#525)
james-garner-canonical Jun 16, 2026
9b688a1
docs(interfaces/istio_metadata): correct docs URL (#531)
james-garner-canonical Jun 16, 2026
7f5e74b
chore(service-mesh): updates the lib folder names to match charmcraft…
adhityaravi Jun 17, 2026
7b2e7bc
fix(nginx-k8s): sort upstream server addresses for stable nginx confi…
Copilot Jun 19, 2026
5c114e1
docs: update repository links for TLS interfaces (#526)
james-garner-canonical Jun 22, 2026
485159e
docs: migrate TLS certificates docs from Discourse (#516)
james-garner-canonical Jun 22, 2026
7e8edcc
chore(rollingops): update README (#536)
patriciareinoso Jun 22, 2026
9c08cc7
feat!: NginxPrometheusExporter configures TLS (#539)
sinapah Jun 22, 2026
10449eb
fix: _tls_config CA cert path (#543)
sinapah Jun 22, 2026
865da59
ci: exclude certain 'global' files from triggering all package tests …
james-garner-canonical Jun 23, 2026
a78a99a
docs: add PR templates (#542)
james-garner-canonical Jun 23, 2026
ac53655
ci: normalize extension for zizmor config (#550)
james-garner-canonical Jun 23, 2026
2538374
docs: move docs to canonical.com/juju/docs/charmlibs (#515)
dwilding Jun 23, 2026
1a850a9
chore: update codeowners nginx k8s (#554)
sinapah Jun 23, 2026
5caebcd
docs: update Charmlibs URLs for Service Mesh team packages (#555)
dwilding Jun 24, 2026
842505d
docs: update Charmlibs URLs for sloth (#558)
dwilding Jun 24, 2026
058f57e
ci: update workshop definitions (#560)
james-garner-canonical Jun 25, 2026
dda7f0b
docs: update Charmlibs URL for k8s_backup_target (#556)
dwilding Jun 26, 2026
3887f8c
docs: populate lib fields for mlops interfaces (#507)
james-garner-canonical Jun 26, 2026
5f5810f
docs: update project URLs for OTLP lib (#529)
james-garner-canonical Jun 26, 2026
fee3148
docs(interfaces/k8s_backup_target): update project URLs (#527)
james-garner-canonical Jun 26, 2026
aa70acb
docs: populate lib fields for data interfaces (#508)
james-garner-canonical Jun 26, 2026
f9d998f
chore
MichaelThamm Jun 26, 2026
9f0a911
Merge branch 'main' into feat/sigma-rules
MichaelThamm Jun 26, 2026
0e0e159
Merge branch 'feat/sigma-rules' into feat/sigma-rules-2
MichaelThamm Jun 26, 2026
7dbe60f
chore
MichaelThamm Jun 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions interfaces/otlp/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Separated the package into 2 private modules: _otlp and _rules
- Enable user-defined rule labels

## [0.6.0]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure this is the correct version before merging


### Added

- Sigma rules in databag via the `RuleStore` API
5 changes: 4 additions & 1 deletion interfaces/otlp/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ classifiers = [
dynamic = ["version"]
dependencies = [
# "ops",
"cosl>=1.6.1",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove when done testing

"cosl @ git+https://github.com/canonical/cos-lib@feat/sigma-rules-2",
"requests",
]

Expand Down Expand Up @@ -44,6 +44,9 @@ integration = [ # installed for `just integration otlp`
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.metadata]
allow-direct-references = true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove when done testing


[tool.hatch.build.targets.wheel]
packages = ["src/charmlibs"]

Expand Down
4 changes: 4 additions & 0 deletions interfaces/otlp/src/charmlibs/interfaces/otlp/_otlp.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure that the docs render well once built, before merging

Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ def publish(self):
'rules': {
'logql': self._rules.logql.as_dict(),
'promql': self._rules.promql.as_dict(),
'sigma': self._rules.sigma.as_dict(),
},
'metadata': self._topology.as_dict(),
})
Expand Down Expand Up @@ -337,6 +338,9 @@ def rules(self) -> dict[int, RuleStore]:
rules.logql.add(logql_result.rules)
if promql_result.rules and not promql_result.errmsg:
rules.promql.add(promql_result.rules)
# Sigma rules: inject topology labels (no expression rewriting needed)
if sigma_dict := requirer.rules.sigma:
rules.sigma.add(sigma_dict)
for errmsg in [logql_result.errmsg, promql_result.errmsg]:
if errmsg and self._charm.unit.is_leader():
relation.data[self._charm.app]['event'] = json.dumps({'errors': errmsg})
Expand Down
47 changes: 45 additions & 2 deletions interfaces/otlp/src/charmlibs/interfaces/otlp/_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,19 @@
from pathlib import Path

from cosl.juju_topology import JujuTopology
from cosl.rules import HOST_METRICS_MISSING_RULE_NAME, CosTool, Rules, generic_alert_groups
from cosl.types import OfficialRuleFileFormat, SingleRuleFormat
from cosl.rules import (
HOST_METRICS_MISSING_RULE_NAME,
CosTool,
Rules,
SigmaRules,
generic_alert_groups,
)
from cosl.types import (
OfficialRuleFileFormat,
SigmaRuleFileFormat,
SigmaRuleFormat,
SingleRuleFormat,
)
from ops import CharmBase
from pydantic import BaseModel, Field

Expand All @@ -43,10 +54,12 @@ class RuleStore:
topology: JujuTopology
logql: Rules = field(init=False)
promql: Rules = field(init=False)
sigma: SigmaRules = field(init=False)

def __post_init__(self):
self.logql = Rules(query_type='logql', topology=self.topology)
self.promql = Rules(query_type='promql', topology=self.topology)
self.sigma = SigmaRules(topology=self.topology)

def add_logql(
self,
Expand Down Expand Up @@ -110,12 +123,36 @@ def add_promql_path(self, dir_path: str | Path, *, recursive: bool = False) -> '
self.promql.add_path(dir_path, recursive=recursive)
return self

def add_sigma(self, rule_dict: SigmaRuleFileFormat | SigmaRuleFormat) -> 'RuleStore':
"""Add rules from dict to the existing Sigma ruleset.

Args:
rule_dict: a single sigma rule dict or a ``{"rules": [...]}`` collection.
"""
self.sigma.add(rule_dict)
return self

def add_sigma_path(self, dir_path: str | Path, *, recursive: bool = False) -> 'RuleStore':
"""Add Sigma rules from a dir path.

All rules from files are aggregated into a single collection.
Topology labels are injected into each rule.

Args:
dir_path: either a rules file or a dir of rules files.
recursive: whether to read files recursively or not (no impact if `path` is a file).
"""
self.sigma.add_path(dir_path, recursive=recursive)
return self

def combine(self, other: 'RuleStore') -> 'RuleStore':
"""Combine rules from another RuleStore with this RuleStore."""
if other_logql := other.logql.as_dict():
self.logql.add(other_logql)
if other_promql := other.promql.as_dict():
self.promql.add(other_promql)
if other_sigma := other.sigma.as_dict():
self.sigma.add(other_sigma)
return self


Expand All @@ -132,6 +169,10 @@ class _RulesModel(BaseModel):
'OfficialRuleFileFormat from cos-lib.',
default_factory=OfficialRuleFileFormat,
)
sigma: SigmaRuleFileFormat = Field(
description='Sigma detection rules, following the SigmaRuleFileFormat from cos-lib.',
default_factory=SigmaRuleFileFormat,
)


def duplicate_rules_per_unit(
Expand Down Expand Up @@ -235,4 +276,6 @@ def inject_extra_labels_into_rules(
for group in rule_groups.get('groups', []):
for rule in group.get('rules', []):
rule.setdefault('labels', {}).update(extra_alert_labels)
for sigma_rule in rules_copy.sigma.as_dict().get('rules', []):
sigma_rule.setdefault('labels', {}).update(extra_alert_labels)
return rules_copy
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.

__version__ = '0.5.0'
__version__ = '0.6.0'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure this is the correct version before merging

29 changes: 28 additions & 1 deletion interfaces/otlp/tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@
import ops
import pytest
from cosl.juju_topology import JujuTopology
from cosl.types import AlertingRuleFormat, OfficialRuleFileFormat, RecordingRuleFormat
from cosl.types import (
AlertingRuleFormat,
OfficialRuleFileFormat,
RecordingRuleFormat,
SigmaRuleFormat,
)
from ops import testing
from ops.charm import CharmBase

Expand Down Expand Up @@ -74,6 +79,26 @@
},
]
)
SINGLE_SIGMA_RULE: SigmaRuleFormat = {
'title': 'Failed SSH Login Attempt',
'id': '5f3a4e20-1b2c-4d5e-9f8a-7b6c3d4e5f6a',
'status': 'experimental',
'logsource': {'category': 'authentication', 'product': 'linux', 'service': 'sshd'},
'detection': {'selection': {'event_type': 'authentication_failure'}, 'condition': 'selection'},
'level': 'medium',
}
SIGMA_COLLECTION: dict = {
'rules': [
SINGLE_SIGMA_RULE,
{
'title': 'High CPU Usage',
'logsource': {'category': 'process_monitoring', 'product': 'linux'},
'detection': {'selection': {'metric': 'cpu_percent'}, 'condition': 'selection'},
'level': 'high',
},
]
}

ALL_PROTOCOLS: list[Literal['grpc', 'http']] = ['grpc', 'http']
ALL_TELEMETRIES: list[Literal['logs', 'metrics', 'traces']] = ['logs', 'metrics', 'traces']

Expand Down Expand Up @@ -102,6 +127,8 @@ def _publish_rules(self, _: ops.EventBase) -> None:
.add_promql(deepcopy(SINGLE_PROMQL_RECORD), group_name='test_promql_record')
.add_logql(deepcopy(OFFICIAL_LOGQL_RULES))
.add_promql(deepcopy(OFFICIAL_PROMQL_RULES))
.add_sigma(deepcopy(SINGLE_SIGMA_RULE))
.add_sigma(deepcopy(SIGMA_COLLECTION))
)
OtlpRequirer(
self,
Expand Down
Loading
Loading