Skip to content

feat: kafka message dispatcher #1641

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 174 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from 170 commits
Commits
Show all changes
174 commits
Select commit Hold shift + click to select a range
22bef44
Draft kafka consumer specs
nas-tabchiche Mar 7, 2025
fadfe5e
Consumer initial commit
nas-tabchiche Mar 7, 2025
e81376a
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 7, 2025
e1b3ecc
Event consumption PoC
nas-tabchiche Mar 7, 2025
65e97d2
Implement event registry
nas-tabchiche Mar 10, 2025
feaa018
Update applied control PoC
nas-tabchiche Mar 11, 2025
d085c68
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 11, 2025
7602aba
Add selectors docs
nas-tabchiche Mar 12, 2025
2d5c1a0
Add ref_id to applied control filterset
nas-tabchiche Mar 12, 2025
729e9e1
Switch package-mode to false
nas-tabchiche Mar 12, 2025
5e2e08c
Implement selector processing
nas-tabchiche Mar 12, 2025
742ea0f
Update .gitignore
nas-tabchiche Mar 12, 2025
d427aa3
Tidy selector management
nas-tabchiche Mar 12, 2025
5584c73
Generalize applied control update
nas-tabchiche Mar 12, 2025
0a6f097
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 12, 2025
85438fa
Update exception body
nas-tabchiche Mar 12, 2025
15c90e0
Generalize update_object function
nas-tabchiche Mar 12, 2025
0289915
Manage selector key mappings
nas-tabchiche Mar 12, 2025
c70f3e6
Add required filterset_fields to requirement assessments viewset
nas-tabchiche Mar 12, 2025
02edaa2
Add folder__name filter to requirement assessments
nas-tabchiche Mar 13, 2025
94951a2
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 13, 2025
c5051f9
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 13, 2025
ebfd636
Rename consumer to dispatcher
nas-tabchiche Mar 14, 2025
fcb26dd
Add redpanda docker-compose file
nas-tabchiche Mar 14, 2025
a28c78a
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 14, 2025
9826ff7
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 18, 2025
5571fed
Implement attachment upload use case
nas-tabchiche Mar 18, 2025
bea0ad0
Pluralize update_object function
nas-tabchiche Mar 18, 2025
124d811
Register upload_attachment command
nas-tabchiche Mar 18, 2025
083f169
Add update applied control and requirement assessment avro schemas
nas-tabchiche Mar 18, 2025
c8f865a
Distinguish events and commands
nas-tabchiche Mar 18, 2025
3842f06
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 19, 2025
7a2a212
Rename event_type to message_type
nas-tabchiche Mar 19, 2025
59eeb84
Update pyproject.toml
nas-tabchiche Mar 19, 2025
0b88113
Use json instead of data
nas-tabchiche Mar 19, 2025
c965170
Avoid mutable default argument
nas-tabchiche Mar 19, 2025
d304699
Use b64decode
nas-tabchiche Mar 19, 2025
d303fe2
Some error handling
nas-tabchiche Mar 19, 2025
953e943
Try out loguru for logging
nas-tabchiche Mar 19, 2025
3c72b87
Avro PoC
nas-tabchiche Mar 19, 2025
35c221d
Migrate to avro
nas-tabchiche Mar 19, 2025
0231aca
Add rich logging
nas-tabchiche Mar 19, 2025
5304076
Add upload attachment avro schema
nas-tabchiche Mar 19, 2025
ab0ec85
Revert to json messages
nas-tabchiche Mar 19, 2025
2317bab
Produce errors to ERRORS_TOPIC
nas-tabchiche Mar 19, 2025
daf4789
Convert AVRO schemas to JSON
nas-tabchiche Mar 19, 2025
fdbea08
Remove done TODO
nas-tabchiche Mar 19, 2025
f7c5abe
Include exception message with produced error message
nas-tabchiche Mar 19, 2025
7dee475
sample 1
ab-smith Mar 20, 2025
fd2ac06
integration layer starting point
ab-smith Mar 20, 2025
31af79e
wip
ab-smith Mar 20, 2025
b6c2a4c
Provide a clearer error message for selector errors
nas-tabchiche Mar 21, 2025
3ebe71b
Improve log message format
nas-tabchiche Mar 21, 2025
09f7f0f
Use regular ISO8601 for timestamps
nas-tabchiche Mar 21, 2025
b6a017b
Include exception trace on message failure
nas-tabchiche Mar 21, 2025
a0a89db
Manage object storage for attachment upload
nas-tabchiche Mar 21, 2025
fddd816
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 21, 2025
89cdc28
Write requests wrapper helpers
nas-tabchiche Mar 21, 2025
2ab447e
Improve settings and add -y flag to init-config
nas-tabchiche Mar 21, 2025
a70f619
Containerize dispatcher
nas-tabchiche Mar 21, 2025
d3fb2bc
Switch to uv for dependency management
nas-tabchiche Mar 21, 2025
3d03978
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 21, 2025
de43a35
testcontainers starting point
nas-tabchiche Mar 24, 2025
90592b8
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 24, 2025
e827277
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 26, 2025
601fa67
dockerignore .venv
nas-tabchiche Mar 26, 2025
685ce6d
wip
nas-tabchiche Mar 26, 2025
245f95d
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 27, 2025
c7fd9b5
Remove unnecessary steps
nas-tabchiche Mar 27, 2025
77dddf0
rename kafka_brokers to bootstrap_servers
nas-tabchiche Mar 27, 2025
7994c7b
remove poetry.lock
nas-tabchiche Mar 28, 2025
ea8312c
remove redpanda directory
nas-tabchiche Mar 28, 2025
b71cfa4
use kafka instead of redpanda for examples
nas-tabchiche Mar 28, 2025
eea7d43
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 28, 2025
8aa93dd
properly package dispatcher using docker compose
nas-tabchiche Mar 28, 2025
24dcb0b
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Mar 28, 2025
7730001
use ISO_9001 ref_id for demo compliance assessment
nas-tabchiche Mar 28, 2025
65e706f
Write README
nas-tabchiche Mar 28, 2025
044fdb0
basic redpanda deployment
ab-smith Mar 30, 2025
fe79a34
Merge branch 'main' into experiment/kafka-consumer
ab-smith Mar 30, 2025
62b6407
remove duplicates
ab-smith Mar 30, 2025
f725709
Merge branch 'main' into experiment/kafka-consumer
ab-smith Mar 30, 2025
73e91e3
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 1, 2025
26c6a23
Merge branch 'main' into experiment/kafka-consumer
ab-smith Apr 4, 2025
dcbb8fd
wip
nas-tabchiche Apr 6, 2025
d534183
Add enterprise fullstack docker compose
nas-tabchiche Apr 6, 2025
f26dfd4
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 6, 2025
1aa37c4
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 7, 2025
d9ca00f
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 7, 2025
4f49054
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 8, 2025
a95f68a
remove dead code
nas-tabchiche Apr 8, 2025
08fc5a5
allow silent reauthentication
nas-tabchiche Apr 8, 2025
3f2e69f
get auth token lazily
nas-tabchiche Apr 8, 2025
85236a4
rename check_auth to get_access_token
nas-tabchiche Apr 8, 2025
ccd4929
wrap message processing in inner retry loop
nas-tabchiche Apr 8, 2025
24d9857
streamline config across .dispatcher_config.yaml and environment vari…
nas-tabchiche Apr 9, 2025
1fbc358
provide sensible defaults for dispatcher service in docker compose
nas-tabchiche Apr 9, 2025
9435451
add samples/messages directory
nas-tabchiche Apr 9, 2025
81e4887
move stuff around
nas-tabchiche Apr 9, 2025
c314649
write compose build script
nas-tabchiche Apr 9, 2025
1cdab0c
wrap superuser password assignment in retry loop
nas-tabchiche Apr 9, 2025
246ea27
attempt to get access token from environment before checking tmp file
nas-tabchiche Apr 10, 2025
eecde72
update docstrings
nas-tabchiche Apr 10, 2025
50a3f96
add interactive config init
nas-tabchiche Apr 10, 2025
f6fbbaa
add shorthand for interactive flag
nas-tabchiche Apr 10, 2025
d7926e8
send files through request.data
nas-tabchiche Apr 10, 2025
df83fdc
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 14, 2025
840545b
Add dispatcher service in config builder
nas-tabchiche Apr 14, 2025
186c83c
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 14, 2025
29d0be5
add kafka bootstrap servers setting to init-config command
nas-tabchiche Apr 15, 2025
829940b
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 15, 2025
f48c46d
properly manage s3 access token and secret
nas-tabchiche Apr 15, 2025
3107ce2
log bootstrap servers url on startup
nas-tabchiche Apr 15, 2025
af462f5
improve error handling on consumer/producer start
nas-tabchiche Apr 16, 2025
c6cca1d
add some docs
nas-tabchiche Apr 16, 2025
68e7b1f
put token config under credentials category
nas-tabchiche Apr 16, 2025
aee4fd1
write startup tests for api and kafka
nas-tabchiche Apr 16, 2025
c55b085
update readme
nas-tabchiche Apr 16, 2025
0499e9a
add test for dispatcher auth
nas-tabchiche Apr 17, 2025
491938c
Merge branch 'main' into experiment/kafka-consumer
nas-tabchiche Apr 17, 2025
a543cd5
update readme
nas-tabchiche Apr 17, 2025
45edfa4
update readme
nas-tabchiche Apr 17, 2025
748c450
update redpanda basic docker compose
nas-tabchiche Apr 17, 2025
6ce1620
manage kafka authentication
nas-tabchiche Apr 17, 2025
96e8567
update config buildeer
nas-tabchiche Apr 17, 2025
2a1ce46
clarify config prompts
nas-tabchiche Apr 17, 2025
ecd56ec
update readme
nas-tabchiche Apr 17, 2025
cc1ddb7
fix auto session renewal
nas-tabchiche Apr 17, 2025
f05c146
preserve original exception context
nas-tabchiche Apr 17, 2025
4626100
anonymize unused loop variable
nas-tabchiche Apr 17, 2025
c597468
fix code block type for JSON example
nas-tabchiche Apr 17, 2025
0390b2a
update readme
nas-tabchiche Apr 17, 2025
ec420f7
set -e on dispatcher/startup.sh
nas-tabchiche Apr 17, 2025
a4a5563
fix mutable default arguments
nas-tabchiche Apr 17, 2025
e18ac3d
remove full stack + dispatcher + kafka docker compose files
nas-tabchiche Apr 17, 2025
f3981e7
remove dead code
nas-tabchiche Apr 17, 2025
446fb31
remove comments
nas-tabchiche Apr 17, 2025
f35e745
fix infinite retry loop on error responses with status other than 401
nas-tabchiche Apr 17, 2025
5db4e46
close consumer at the end
nas-tabchiche Apr 17, 2025
173d9c3
stop logging full config
nas-tabchiche Apr 17, 2025
66e209b
Guard against None coming back from process_selector
nas-tabchiche Apr 17, 2025
1fa3432
Prefer json= over manual data=json.dumps()
nas-tabchiche Apr 17, 2025
52f1aab
Use package‑relative imports
nas-tabchiche Apr 17, 2025
5fe7032
fix DEBUG env var is stored as string, not boolean
nas-tabchiche Apr 17, 2025
43e5576
avoid logging full response
nas-tabchiche Apr 17, 2025
362c8cc
Handle potential missing 'id' field
nas-tabchiche Apr 17, 2025
6fecaf6
Add timeout to API requests and improve error handling
nas-tabchiche Apr 17, 2025
b564cf4
use explicit relative imports
nas-tabchiche Apr 17, 2025
81f6ca3
rename startup.sh to entrypoint.sh
nas-tabchiche Apr 17, 2025
aaa46d7
improve message schemas
nas-tabchiche Apr 17, 2025
a945010
replace file_s3_key with file_name
nas-tabchiche Apr 17, 2025
89ea127
handle case where session token update fails
nas-tabchiche Apr 17, 2025
49d9fad
update upload attachment json schema
nas-tabchiche Apr 17, 2025
6134a16
set default request timeout to 30 sec
nas-tabchiche Apr 17, 2025
ee31717
use requests wrapper
nas-tabchiche Apr 17, 2025
0c878dc
Use shared session token instead of retrieving a new token
nas-tabchiche Apr 17, 2025
168b678
Update dispatcher/tests/integration/test_messages.py
nas-tabchiche Apr 17, 2025
a24dc24
Merge branch 'experiment/kafka-consumer' of github.com:intuitem/ciso-…
nas-tabchiche Apr 17, 2025
290e599
fix applied_controls selector type mismatch
nas-tabchiche Apr 17, 2025
68eaa82
fix credentials validation blocking token‑only auth
nas-tabchiche Apr 17, 2025
8fb4548
exit 1 on authentication failure
nas-tabchiche Apr 17, 2025
459a534
initialize s3 variables
nas-tabchiche Apr 17, 2025
4e232d8
Enhance error handling with pipefail
nas-tabchiche Apr 17, 2025
8847fe0
fixup
nas-tabchiche Apr 23, 2025
b7d83c0
Merge branch 'main' into experiment/kafka-consumer
ab-smith Apr 23, 2025
6c2f864
improve config questionnaire
nas-tabchiche Apr 23, 2025
0d09bb0
set default value to blank for s3 url
nas-tabchiche Apr 23, 2025
51226dc
add setting for kafka sasl mechanism
nas-tabchiche Apr 23, 2025
82e834b
update readme
nas-tabchiche Apr 23, 2025
07532b9
strip trailing slash from API url
nas-tabchiche Apr 23, 2025
bbf7223
update readme
nas-tabchiche Apr 23, 2025
a20636d
fixup
ab-smith Apr 23, 2025
d4cb71c
fixup
ab-smith Apr 23, 2025
d0c8ba5
fixup
ab-smith Apr 23, 2025
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
1 change: 1 addition & 0 deletions backend/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
.git*
.pytest*
.idea*
.venv
.dockerignore
Dockerfile
db
Expand Down
5 changes: 5 additions & 0 deletions backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,7 @@ class Meta:
"owner": ["exact"],
"findings": ["exact"],
"eta": ["exact", "lte", "gte", "lt", "gt", "month", "year"],
"ref_id": ["exact"],
}


Expand Down Expand Up @@ -4544,10 +4545,14 @@ class RequirementAssessmentViewSet(BaseModelViewSet):
model = RequirementAssessment
filterset_fields = [
"folder",
"folder__name",
"evidences",
"compliance_assessment",
"applied_controls",
"security_exceptions",
"requirement__ref_id",
"compliance_assessment__ref_id",
"compliance_assessment__assets__ref_id",
]
search_fields = ["requirement__name", "requirement__description"]

Expand Down
97 changes: 91 additions & 6 deletions config/make_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,88 @@ def get_config():
).ask(),
}

# Kafka Dispatcher Configuration
enable_dispatcher = questionary.confirm(
"Would you like to configure the Kafka dispatcher? This requires a kafka broker to be running.",
default=False,
).ask()

if enable_dispatcher:
config["kafka_dispatcher"] = {
"enabled": True,
"broker_url": questionary.text(
"Enter the Kafka broker URL (e.g., localhost:9092):",
default="localhost:9092",
).ask(),
"observation_topic": questionary.text(
"Enter the Kafka topic for dispatcher events (e.g., observation):",
default="observation",
).ask(),
"errors_topic": questionary.text(
"Enter the topic name for error messages (e.g., errors):",
default="errors",
).ask(),
"authentication": questionary.select(
"How would you like to authenticate requests to the CISO Assistant API using the dispatcher (credentials/token)?",
choices=["credentials", "token"],
default="credentials",
).ask(),
}
if config["kafka_dispatcher"]["authentication"] == "credentials":
config["kafka_dispatcher"]["credentials"] = {
"user_email": questionary.text(
"Enter the email of the CISO Assistant user account"
).ask(),
"user_password": questionary.password(
"Enter the password of the CISO Assistant user account"
).ask(),
}
config["kafka_dispatcher"]["auto_renew_session"] = questionary.confirm(
"Enable silent reauthentication to the CISO Assistant API on session expiry?",
default=True,
).ask()
elif config["kafka_dispatcher"]["authentication"] == "token":
config["kafka_dispatcher"]["token"] = questionary.password(
"Enter access token"
).ask()
kafka_use_auth = questionary.confirm(
"Does your Kafka broker require authentication?",
default=False,
).ask()
config["kafka_dispatcher"]["use_auth"] = kafka_use_auth
if kafka_use_auth:
config["kafka_dispatcher"]["sasl_mechanism"] = "PLAIN"
config["kafka_dispatcher"]["sasl_username"] = questionary.text(
"Enter the username of your Kafka service account"
).ask()
config["kafka_dispatcher"]["sasl_password"] = questionary.password(
"Enter the password of your Kafka service account"
).ask()

use_s3 = questionary.confirm(
"Would you like to connect a S3 bucket to the dispatcher? This can be used e.g. to upload files to the CISO Assistant backend.",
default=True,
).ask()

config["kafka_dispatcher"]["s3_url"] = ""
config["kafka_dispatcher"]["s3_access_key"] = ""
config["kafka_dispatcher"]["s3_secret_key"] = ""
if use_s3:
config["kafka_dispatcher"]["s3_url"] = questionary.text(
"Enter the S3 storage URL (e.g., http://localhost:9000)",
default="http://localhost:9000",
).ask()
config["kafka_dispatcher"]["s3_access_key"] = questionary.text(
"Enter the S3 access key (leave blank if using public S3 storage)",
).ask()
config["kafka_dispatcher"]["s3_secret_key"] = ""
if config["kafka_dispatcher"]["s3_access_key"]:
config["kafka_dispatcher"]["s3_secret_key"] = questionary.password(
"Enter the S3 secret key",
).ask()
else:
config["kafka_dispatcher"] = {"enabled": False}

# Debug mode for local development
config["enable_debug"] = questionary.confirm(
"Enable debug mode?", default=True if config["db"] == "sqlite" else False
Expand All @@ -105,22 +187,25 @@ def generate_compose_file(config):
except Exception as e:
print(f"[red]Error: Template {template_name} not found![/red]")
print(
f"[yellow]Please ensure you have the following template file in your templates directory:[/yellow]"
"[yellow]Please ensure you have the following template file in your templates directory:[/yellow]"
)
print(f"[yellow]templates/{template_name}[/yellow]")
print(
f"[yellow]Expected template name format: docker-compose-local-<db>-<proxy>.yml.j2[/yellow]"
"[yellow]Expected template name format: docker-compose-local-<db>-<proxy>.yml.j2[/yellow]"
)
print(f"[yellow]Where <db> is one of: sqlite, postgresql[/yellow]")
print(f"[yellow]And <proxy> is one of: caddy, traefik[/yellow]")
print("[yellow]Where <db> is one of: sqlite, postgresql[/yellow]")
print("[yellow]And <proxy> is one of: caddy, traefik[/yellow]")
raise e

# Render template with configuration
compose_content = template.render(config)

lines = compose_content.splitlines()
filtered = [line for line in lines if line.strip() != ""]

# Write to docker-compose-custom.yml
with open("docker-compose-custom.yml", "w") as f:
f.write(compose_content)
f.write("\n".join(filtered))


def validate_cert_paths(config):
Expand Down Expand Up @@ -170,7 +255,7 @@ def main():
if config["need_mailer"]:
print("4. Verify email configuration settings")
print(
f"5. Run './docker-compose.sh' and follow the instructions to create the first admin user"
"5. Run './docker-compose.sh' and follow the instructions to create the first admin user"
)
print(f"6. Access the application at https://{config['fqdn']}:{config['port']}")

Expand Down
35 changes: 35 additions & 0 deletions config/templates/docker-compose-postgresql-caddy.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,38 @@ services:
tls /etc/caddy/cert.pem /etc/caddy/key.pem{% else %}
tls internal{% endif %}{% endif %}
}" > Caddyfile && caddy run'

{% if kafka_dispatcher.enabled %}
dispatcher:
container_name: dispatcher
image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:latest
# build:
# context: ../dispatcher
restart: always
environment:
- API_URL=http://backend:8000/api
- BOOTSTRAP_SERVERS={{ kafka_dispatcher.broker_url }}
- KAFKA_USE_AUTH={{ kafka_dispatcher.kafka_use_auth }}
{% if kafka_dispatcher.kafka_use_auth %}
- KAFKA_SASL_MECHANISM={{ kafka_dispatcher.kafka_sasl_mechanism }}
- KAFKA_USERNAME={{ kafka_dispatcher.kafka_username }}
- KAFKA_PASSWORD={{ kafka_dispatcher.kafka_password }}
{% endif %}
- OBSERVATION_TOPIC={{ kafka_dispatcher.observation_topic }}
- ERRORS_TOPIC={{ kafka_dispatcher.errors_topic }}
{% if kafka_dispatcher.authentication == 'credentials' %}
- USER_EMAIL={{ kafka_dispatcher.credentials.user_email }}
- USER_PASSWORD={{ kafka_dispatcher.credentials.user_password }}
- AUTO_RENEW_SESSION={{ kafka_dispatcher.auto_renew_session }}
{% elif kafka_dispatcher.authentication == 'token' %}
- TOKEN={{ kafka_dispatcher.token }}
{% endif %}
{% if kafka_dispatcher.s3_url %}
- S3_URL={{ kafka_dispatcher.s3_url }}
- S3_ACCESS_KEY={{ kafka_dispatcher.s3_access_key }}
- S3_SECRET_KEY={{ kafka_dispatcher.s3_secret_key }}
{% endif %}
depends_on:
backend:
condition: service_healthy
{% endif %}
35 changes: 35 additions & 0 deletions config/templates/docker-compose-postgresql-traefik.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,38 @@ services:
- "--providers.file.directory=/etc/traefik"
- "--providers.file.watch=true"{% else %}
- "--experimental.localPlugins.selfsigned.moduleName=traefik.tls"{% endif %}

{% if kafka_dispatcher.enabled %}
dispatcher:
container_name: dispatcher
image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:latest
# build:
# context: ../dispatcher
restart: always
environment:
- API_URL=http://backend:8000/api
- BOOTSTRAP_SERVERS={{ kafka_dispatcher.broker_url }}
- KAFKA_USE_AUTH={{ kafka_dispatcher.kafka_use_auth }}
{% if kafka_dispatcher.kafka_use_auth %}
- KAFKA_SASL_MECHANISM={{ kafka_dispatcher.kafka_sasl_mechanism }}
- KAFKA_USERNAME={{ kafka_dispatcher.kafka_username }}
- KAFKA_PASSWORD={{ kafka_dispatcher.kafka_password }}
{% endif %}
- OBSERVATION_TOPIC={{ kafka_dispatcher.observation_topic }}
- ERRORS_TOPIC={{ kafka_dispatcher.errors_topic }}
{% if kafka_dispatcher.authentication == 'credentials' %}
- USER_EMAIL={{ kafka_dispatcher.credentials.user_email }}
- USER_PASSWORD={{ kafka_dispatcher.credentials.user_password }}
- AUTO_RENEW_SESSION={{ kafka_dispatcher.auto_renew_session }}
{% elif kafka_dispatcher.authentication == 'token' %}
- TOKEN={{ kafka_dispatcher.token }}
{% endif %}
{% if kafka_dispatcher.s3_url %}
- S3_URL={{ kafka_dispatcher.s3_url }}
- S3_ACCESS_KEY={{ kafka_dispatcher.s3_access_key }}
- S3_SECRET_KEY={{ kafka_dispatcher.s3_secret_key }}
{% endif %}
depends_on:
backend:
condition: service_healthy
{% endif %}
35 changes: 35 additions & 0 deletions config/templates/docker-compose-sqlite-caddy.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,38 @@ services:
tls /etc/caddy/cert.pem /etc/caddy/key.pem{% else %}
tls internal{% endif %}{% endif %}
}" > Caddyfile && caddy run'

{% if kafka_dispatcher.enabled %}
dispatcher:
container_name: dispatcher
image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:latest
# build:
Comment on lines +98 to +99
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using 'latest' tag in production deployments.

Using the 'latest' tag can lead to unexpected changes and inconsistent deployments, making version tracking and rollbacks difficult.

    container_name: dispatcher
-   image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:latest
+   image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:${DISPATCHER_VERSION:-latest}
    # build:
    #   context: ../dispatcher

Consider either:

  1. Pinning to a specific version tag
  2. Using an environment variable with a default value as shown in the diff
  3. Using the same version tagging strategy used for other services in this file
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:latest
# build:
container_name: dispatcher
image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:${DISPATCHER_VERSION:-latest}
# build:
# context: ../dispatcher

# context: ../dispatcher
restart: always
environment:
- API_URL=http://backend:8000/api
- BOOTSTRAP_SERVERS={{ kafka_dispatcher.broker_url }}
- KAFKA_USE_AUTH={{ kafka_dispatcher.kafka_use_auth }}
{% if kafka_dispatcher.kafka_use_auth %}
- KAFKA_SASL_MECHANISM={{ kafka_dispatcher.kafka_sasl_mechanism }}
- KAFKA_USERNAME={{ kafka_dispatcher.kafka_username }}
- KAFKA_PASSWORD={{ kafka_dispatcher.kafka_password }}
{% endif %}
- OBSERVATION_TOPIC={{ kafka_dispatcher.observation_topic }}
- ERRORS_TOPIC={{ kafka_dispatcher.errors_topic }}
{% if kafka_dispatcher.authentication == 'credentials' %}
- USER_EMAIL={{ kafka_dispatcher.credentials.user_email }}
- USER_PASSWORD={{ kafka_dispatcher.credentials.user_password }}
- AUTO_RENEW_SESSION={{ kafka_dispatcher.auto_renew_session }}
{% elif kafka_dispatcher.authentication == 'token' %}
- TOKEN={{ kafka_dispatcher.token }}
{% endif %}
{% if kafka_dispatcher.s3_url %}
- S3_URL={{ kafka_dispatcher.s3_url }}
- S3_ACCESS_KEY={{ kafka_dispatcher.s3_access_key }}
- S3_SECRET_KEY={{ kafka_dispatcher.s3_secret_key }}
{% endif %}
Comment on lines +105 to +124
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use environment file or secrets for sensitive credentials

The current configuration embeds passwords and authentication tokens directly in environment variables, which could expose sensitive information in logs or error messages.

      - KAFKA_USE_AUTH={{ kafka_dispatcher.kafka_use_auth }}
      {% if kafka_dispatcher.kafka_use_auth %}
-      - KAFKA_SASL_MECHANISM={{ kafka_dispatcher.kafka_sasl_mechanism }}
-      - KAFKA_USERNAME={{ kafka_dispatcher.kafka_username }}
-      - KAFKA_PASSWORD={{ kafka_dispatcher.kafka_password }}
+      - KAFKA_SASL_MECHANISM={{ kafka_dispatcher.kafka_sasl_mechanism }}
+    env_file:
+      - ./kafka_dispatcher_credentials.env
      {% endif %}
      - OBSERVATION_TOPIC={{ kafka_dispatcher.observation_topic }}
      - ERRORS_TOPIC={{ kafka_dispatcher.errors_topic }}
      {% if kafka_dispatcher.authentication == 'credentials' %}
-      - USER_EMAIL={{ kafka_dispatcher.credentials.user_email }}
-      - USER_PASSWORD={{ kafka_dispatcher.credentials.user_password }}
+      - USER_EMAIL={{ kafka_dispatcher.credentials.user_email }}
+    secrets:
+      - dispatcher_api_credentials
      - AUTO_RENEW_SESSION={{ kafka_dispatcher.auto_renew_session }}
      {% elif kafka_dispatcher.authentication == 'token' %}
-      - TOKEN={{ kafka_dispatcher.token }}
+    secrets:
+      - dispatcher_api_token
      {% endif %}
      {% if kafka_dispatcher.s3_url %}
      - S3_URL={{ kafka_dispatcher.s3_url }}
-      - S3_ACCESS_KEY={{ kafka_dispatcher.s3_access_key }}
-      - S3_SECRET_KEY={{ kafka_dispatcher.s3_secret_key }}
+    secrets:
+      - dispatcher_s3_credentials
      {% endif %}

Add secrets and env files sections:

services:
  # ... existing services ...
+
+secrets:
+  {% if kafka_dispatcher.enabled %}
+  {% if kafka_dispatcher.authentication == 'credentials' %}
+  dispatcher_api_credentials:
+    file: ./dispatcher_api_credentials.txt
+  {% elif kafka_dispatcher.authentication == 'token' %}
+  dispatcher_api_token:
+    file: ./dispatcher_api_token.txt
+  {% endif %}
+  {% if kafka_dispatcher.s3_url %}
+  dispatcher_s3_credentials:
+    file: ./dispatcher_s3_credentials.txt
+  {% endif %}
+  {% endif %}

Committable suggestion skipped: line range outside the PR's diff.

depends_on:
backend:
condition: service_healthy
{% endif %}
Comment on lines +95 to +128
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Document when to use commented build section

The commented-out build section suggests local building is supported, but it's not clear when users should uncomment it.


🏁 Script executed:

#!/bin/bash
# Check for documentation on when to use the build section instead of the image
grep -r "build.*context.*dispatcher" --include="*.md" dispatcher/
grep -r "locally build" --include="*.md" dispatcher/

Length of output: 122


Document usage of the commented‑out build block

The # build: section in config/templates/docker-compose-sqlite-caddy.yml.j2 implies local‐build support, but there’s no guidance on when to uncomment it.

• In config/templates/docker-compose-sqlite-caddy.yml.j2 (lines 95–128): add an inline comment or link explaining that uncommenting the build block will build the dispatcher locally instead of pulling the image.
• In your main README.md (or a new docs/development.md): include a “Local development” section that describes how and when to enable the build context for the dispatcher.
• Optionally, reference any environment‑specific caveats (e.g., needing Docker Engine installed) when opting into the local build.

35 changes: 35 additions & 0 deletions config/templates/docker-compose-sqlite-traefik.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,38 @@ services:
- "--providers.file.directory=/etc/traefik"
- "--providers.file.watch=true"{% else %}
- "--experimental.localPlugins.selfsigned.moduleName=traefik.tls"{% endif %}

{% if kafka_dispatcher.enabled %}
dispatcher:
container_name: dispatcher
image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:latest
# build:
Comment on lines +119 to +120
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using 'latest' tag in production environments

Using the latest tag can lead to unpredictable deployments as new versions are released without warning. This may cause unexpected behavior or compatibility issues.

Consider using a specific version tag instead:

-    image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:latest
+    image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:1.0.0  # Replace with appropriate version
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:latest
# build:
image: ghcr.io/intuitem/ciso-assistant-community/dispatcher:1.0.0 # Replace with appropriate version
# build:

# context: ../dispatcher
restart: always
environment:
- API_URL=http://backend:8000/api
- BOOTSTRAP_SERVERS={{ kafka_dispatcher.broker_url }}
- KAFKA_USE_AUTH={{ kafka_dispatcher.kafka_use_auth }}
{% if kafka_dispatcher.kafka_use_auth %}
- KAFKA_SASL_MECHANISM={{ kafka_dispatcher.kafka_sasl_mechanism }}
- KAFKA_USERNAME={{ kafka_dispatcher.kafka_username }}
- KAFKA_PASSWORD={{ kafka_dispatcher.kafka_password }}
{% endif %}
- OBSERVATION_TOPIC={{ kafka_dispatcher.observation_topic }}
- ERRORS_TOPIC={{ kafka_dispatcher.errors_topic }}
{% if kafka_dispatcher.authentication == 'credentials' %}
- USER_EMAIL={{ kafka_dispatcher.credentials.user_email }}
- USER_PASSWORD={{ kafka_dispatcher.credentials.user_password }}
- AUTO_RENEW_SESSION={{ kafka_dispatcher.auto_renew_session }}
{% elif kafka_dispatcher.authentication == 'token' %}
- TOKEN={{ kafka_dispatcher.token }}
{% endif %}
{% if kafka_dispatcher.s3_url %}
- S3_URL={{ kafka_dispatcher.s3_url }}
- S3_ACCESS_KEY={{ kafka_dispatcher.s3_access_key }}
- S3_SECRET_KEY={{ kafka_dispatcher.s3_secret_key }}
{% endif %}
depends_on:
backend:
condition: service_healthy
{% endif %}
20 changes: 20 additions & 0 deletions dispatcher/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
*.DS_Store
*~$*
.env
.venv
venv
**/node_modules/
.vscode
*.sqlite3
django_secret_key
temp/
db/
.dccache
/backend/profiles
./backend/ciso_assistant/.meta
caddy_data/
**/dist/
**/.meta
charts/custom-values.yaml
**/charts/*/charts
*.bak
Loading
Loading