Skip to content

Commit 3888974

Browse files
madelondohmenDonnypeammar92underdarknl
authored
Add run-on to Boefje Setup page (#4061)
Co-authored-by: Donny Peeters <donny@bitestreams.com> Co-authored-by: Donny Peeters <46660228+Donnype@users.noreply.github.com> Co-authored-by: ammar92 <ammar.abdulamir@gmail.com> Co-authored-by: Jan Klopper <janklopper+underdark@gmail.com>
1 parent 3248a1c commit 3888974

21 files changed

Lines changed: 335 additions & 49 deletions

File tree

boefjes/boefjes/katalogus/plugins.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
get_plugins_filter_parameters,
1616
)
1717
from boefjes.models import FilterParameters, PaginationParameters, PluginType
18+
from boefjes.sql.db_models import RunOn
1819
from boefjes.sql.plugin_storage import get_plugin_storage
1920
from boefjes.storage.interfaces import DuplicatePlugin, IntegrityError, NotAllowed, PluginStorage
2021

@@ -130,6 +131,7 @@ class BoefjeIn(BaseModel):
130131
boefje_schema: dict | None = None
131132
cron: str | None = None
132133
interval: int | None = None
134+
run_on: list[RunOn] | None = None
133135
oci_image: str | None = None
134136
oci_arguments: list[str] = Field(default_factory=list)
135137

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Add run on field to boefje
2+
3+
Revision ID: fc0295b38184
4+
Revises: 9f48560b0000
5+
Create Date: 2025-02-04 16:43:59.171960
6+
7+
"""
8+
9+
import sqlalchemy as sa
10+
from alembic import op
11+
12+
# revision identifiers, used by Alembic.
13+
revision = "fc0295b38184"
14+
down_revision = "9f48560b0000"
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
run_on = sa.Enum("create", "update", "create_update", name="run_on")
20+
21+
22+
def upgrade() -> None:
23+
# ### commands auto generated by Alembic - please adjust! ###
24+
run_on.create(op.get_bind())
25+
op.add_column("boefje", sa.Column("run_on", run_on, nullable=True))
26+
# ### end Alembic commands ###
27+
28+
29+
def downgrade() -> None:
30+
# ### commands auto generated by Alembic - please adjust! ###
31+
op.drop_column("boefje", "run_on")
32+
run_on.drop(op.get_bind(), checkfirst=False)
33+
# ### end Alembic commands ###

boefjes/boefjes/models.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import datetime
22
from enum import Enum
3+
from functools import total_ordering
34
from typing import Literal
45

56
from croniter import croniter
@@ -8,6 +9,18 @@
89
from pydantic import BaseModel, Field, field_validator
910

1011

12+
# This makes the RunOn sortable when in a list. This is convenient for e.g. the RunOnDB.from_run_ons method, that now
13+
# does not have to take the ordering of a boefje.run_on into account in its match statement. This is especially handy
14+
# once we introduce more RunOn values such as DELETE.
15+
@total_ordering
16+
class RunOn(Enum):
17+
CREATE = "create"
18+
UPDATE = "update"
19+
20+
def __lt__(self, other):
21+
return self.value < other.value
22+
23+
1124
class Organisation(BaseModel):
1225
id: str
1326
name: str
@@ -34,6 +47,7 @@ class Boefje(Plugin):
3447
boefje_schema: dict | None = None
3548
cron: str | None = None
3649
interval: int | None = None
50+
run_on: list[RunOn] | None = None
3751
runnable_hash: str | None = None
3852
oci_image: str | None = None
3953
oci_arguments: list[str] = Field(default_factory=list)

boefjes/boefjes/plugins/kat_export_http/boefje.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,5 @@
55
"consumes": [],
66
"scan_level": 4,
77
"oci_image": "ghcr.io/minvws/openkat/export-http:latest",
8-
"run_on": [
9-
"create",
10-
"update"
11-
]
8+
"run_on": ["create", "update"]
129
}

boefjes/boefjes/sql/db_models.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, UniqueConstraint, types
44
from sqlalchemy.orm import relationship
55

6+
from boefjes.models import RunOn
67
from boefjes.sql.db import SQL_BASE
78

89

@@ -14,6 +15,36 @@ class ScanLevel(Enum):
1415
L4 = 4
1516

1617

18+
class RunOnDB(Enum):
19+
CREATE = "create"
20+
UPDATE = "update"
21+
CREATE_UPDATE = "create_update"
22+
23+
@classmethod
24+
def from_run_ons(cls, run_ons: list[RunOn] | None):
25+
if run_ons is None:
26+
return None
27+
28+
match sorted(run_ons):
29+
case [RunOn.CREATE]:
30+
return cls.CREATE
31+
case [RunOn.UPDATE]:
32+
return cls.UPDATE
33+
case [RunOn.CREATE, RunOn.UPDATE]:
34+
return cls.CREATE_UPDATE
35+
case _:
36+
return None
37+
38+
def to_run_ons(self) -> list[RunOn]:
39+
match self:
40+
case RunOnDB.CREATE:
41+
return [RunOn.CREATE]
42+
case RunOnDB.UPDATE:
43+
return [RunOn.UPDATE]
44+
case RunOnDB.CREATE_UPDATE:
45+
return [RunOn.CREATE, RunOn.UPDATE]
46+
47+
1748
class OrganisationInDB(SQL_BASE):
1849
__tablename__ = "organisation"
1950

@@ -72,6 +103,7 @@ class BoefjeInDB(SQL_BASE):
72103
schema = Column(types.JSON(), nullable=True)
73104
cron = Column(types.String(length=128), nullable=True)
74105
interval = Column(types.Integer, nullable=True)
106+
run_on = Column(types.Enum(*[x.value for x in RunOnDB], name="run_on"), nullable=True)
75107

76108
# Image specifications
77109
oci_image = Column(types.String(length=256), nullable=True)

boefjes/boefjes/sql/plugin_storage.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from boefjes.config import Settings, settings
77
from boefjes.models import Boefje, Normalizer, PluginType
88
from boefjes.sql.db import ObjectNotFoundException, session_managed_iterator
9-
from boefjes.sql.db_models import BoefjeInDB, NormalizerInDB
9+
from boefjes.sql.db_models import BoefjeInDB, NormalizerInDB, RunOnDB
1010
from boefjes.sql.session import SessionMixin
1111
from boefjes.storage.interfaces import NotAllowed, PluginNotFound, PluginStorage
1212

@@ -98,6 +98,7 @@ def _db_normalizer_instance_by_id(self, normalizer_id: str) -> NormalizerInDB:
9898

9999
@staticmethod
100100
def to_boefje_in_db(boefje: Boefje, pk: int | None = None) -> BoefjeInDB:
101+
run_on_db = RunOnDB.from_run_ons(boefje.run_on)
101102
boefje = BoefjeInDB(
102103
plugin_id=boefje.id,
103104
created=boefje.created,
@@ -109,6 +110,7 @@ def to_boefje_in_db(boefje: Boefje, pk: int | None = None) -> BoefjeInDB:
109110
schema=boefje.boefje_schema,
110111
cron=boefje.cron,
111112
interval=boefje.interval,
113+
run_on=run_on_db.value if run_on_db is not None else None,
112114
oci_image=boefje.oci_image,
113115
oci_arguments=boefje.oci_arguments,
114116
version=boefje.version,
@@ -152,6 +154,7 @@ def to_boefje(boefje_in_db: BoefjeInDB) -> Boefje:
152154
boefje_schema=boefje_in_db.schema,
153155
cron=boefje_in_db.cron,
154156
interval=boefje_in_db.interval,
157+
run_on=RunOnDB(boefje_in_db.run_on).to_run_ons() if boefje_in_db.run_on else None,
155158
oci_image=boefje_in_db.oci_image,
156159
oci_arguments=boefje_in_db.oci_arguments,
157160
version=boefje_in_db.version,

boefjes/tests/integration/test_api.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ def test_enable_boefje(test_client, organisation, second_organisation):
8383
assert response.json()["enabled"] is False
8484

8585

86+
def test_run_on(test_client, organisation, second_organisation):
87+
test_client.patch(f"/v1/organisations/{organisation.id}/plugins/export-to-http-api", json={"enabled": True})
88+
89+
response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/export-to-http-api")
90+
assert response.json()["enabled"] is True
91+
assert response.json()["run_on"] == ["create", "update"]
92+
93+
boefje = Boefje(id="test_run_on", name="Run On", static=False, run_on=["create"])
94+
response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.model_dump_json())
95+
assert response.status_code == 201
96+
97+
response = test_client.get(f"/v1/organisations/{organisation.id}/plugins/test_run_on")
98+
assert response.json()["enabled"] is False
99+
assert response.json()["run_on"] == [x.value for x in boefje.run_on]
100+
101+
86102
def test_cannot_add_static_plugin_with_duplicate_name(test_client, organisation):
87103
boefje = Boefje(id="test_plugin", name="DNS records", static=False)
88104
response = test_client.post(f"/v1/organisations/{organisation.id}/plugins", content=boefje.model_dump_json())

boefjes/tests/test_models.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from boefjes.models import RunOn
2+
from boefjes.sql.db_models import RunOnDB
3+
4+
5+
def test_run_on():
6+
assert RunOnDB.from_run_ons([RunOn.CREATE]) == RunOnDB.CREATE
7+
assert RunOnDB.from_run_ons([RunOn.UPDATE]) == RunOnDB.UPDATE
8+
assert RunOnDB.from_run_ons([RunOn.CREATE, RunOn.UPDATE]) == RunOnDB.CREATE_UPDATE
9+
assert RunOnDB.from_run_ons([RunOn.UPDATE, RunOn.CREATE]) == RunOnDB.CREATE_UPDATE
10+
assert RunOnDB.from_run_ons([1]) is None
11+
assert RunOnDB.from_run_ons([]) is None
12+
13+
assert RunOnDB.CREATE.to_run_ons() == [RunOn.CREATE]
14+
assert RunOnDB.UPDATE.to_run_ons() == [RunOn.UPDATE]
15+
assert RunOnDB.CREATE_UPDATE.to_run_ons() == [RunOn.CREATE, RunOn.UPDATE]

mula/scheduler/models/ooi.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ class MutationOperationType(Enum):
99
DELETE = "delete"
1010

1111

12+
class RunOn(Enum):
13+
CREATE = MutationOperationType.CREATE.value
14+
UPDATE = MutationOperationType.UPDATE.value
15+
16+
1217
class ScanProfile(BaseModel):
1318
level: int
1419
reference: str

mula/scheduler/models/plugin.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from pydantic import BaseModel
44

5+
from scheduler.models.ooi import RunOn
6+
57

68
class Plugin(BaseModel):
79
id: str
@@ -19,4 +21,4 @@ class Plugin(BaseModel):
1921
produces: list[str]
2022
cron: str | None = None
2123
interval: int | None = None
22-
run_on: list[str] | None = None
24+
run_on: list[RunOn] | None = None

0 commit comments

Comments
 (0)