Skip to main content

Extension Points

Scanner is designed as an extensible base application. All features work out of the box. Organizations can add custom functionality via three extension points — without modifying core code.

Extensions are typically packaged as vendored Rails Engines.

Scanner.configure

The main configuration DSL, defined in lib/scanner/configuration.rb.

Scanner.configure do |config|
# Swap the probe access class
config.probe_access_class = MyCustomProbeAccess

# Swap the retention strategy
config.retention_strategy_class = MyRetentionStrategy

# Register OAuth providers
config.auth_providers = [:google_oauth2, :github]

# Enable portal export
config.portal_export_enabled = true

# Set a custom validation probe
config.validation_probe = "my_probes.ValidationProbe"
end

Configuration Options

OptionTypeDescription
probe_access_classClassControls which probes are accessible. Default allows all community probes.
retention_strategy_classClassDetermines report retention logic. Default uses RETENTION_DAYS.
auth_providersArrayOAuth provider symbols (e.g., :google_oauth2).
portal_export_enabledBooleanEnables export to an external portal.
validation_probeStringProbe name used for target validation.

Lifecycle Hooks

Register hooks to run at specific points in the scan lifecycle:

Scanner.register_hook(:after_report_process) do |context|
# context contains: report, company, scan
MyNotificationService.notify(context[:report])
end

Run hooks from your own code:

Scanner.run_hooks(:after_report_process, { report: @report, company: current_company })

Available hook events:

  • :after_report_process — after a scan report is processed and saved

BrandConfig.configure

Customize branding and white-labeling, defined in lib/brand_config.rb.

BrandConfig.configure do |config|
config.brand_name = "Acme AI Scanner"
config.logo_path = "acme_logo.svg"
config.font_family = "Inter, sans-serif"
config.powered_by = "Powered by Scanner"
config.host_url = "https://scanner.acme.com"
end

Configuration Options

OptionTypeDescription
brand_nameStringDisplayed in the navbar and page titles
logo_pathStringAsset path to your logo file
font_familyStringCSS font-family for the UI
powered_byStringFooter attribution text
host_urlStringCanonical host URL (used in syslog messages and links)

ProbeSourceRegistry

Register additional probe data sources for SyncProbesJob, defined in app/services/probe_source_registry.rb.

ProbeSourceRegistry.register(MyCustomProbeSource)

Implementing a Probe Source

class MyCustomProbeSource
def self.sync_probes
probe_definitions.each do |probe_data|
probe = Probe.find_or_initialize_by(name: probe_data[:name])
probe.update!(
description: probe_data[:description],
family: probe_data[:family],
tags: probe_data[:tags] || []
)
end
end

def self.probe_definitions
[
{
name: "my_probes.CustomJailbreak",
description: "Tests for custom jailbreak patterns",
family: "jailbreak",
tags: ["custom", "jailbreak"]
}
]
end
end

SyncProbesJob calls .sync_probes on every registered source when it runs. The job runs automatically on boot and can be triggered manually:

docker compose exec scanner rails runner "SyncProbesJob.perform_now"

Listing Registered Sources

ProbeSourceRegistry.sources
# => [GarakCommunityProbeSource, MyCustomProbeSource]