Service configuration

OSA Proxy implementation

This page describes the current OSA Proxy implementation. The archived Java/Spring implementation is available in Archived Java/Spring implementation.

OSA Proxy is configured with the osa-proxy.yml file. The example below shows a typical working configuration with several ecosystems, CodeScoring settings, HTTP client settings, Redis cache, and logging.

Legacy Judge compatibility

For CodeScoring versions earlier than 2026.20.0, set codescoring.legacy-judge: true. Versions before 2026.20.0 use the legacy Judge API, while OSA Proxy uses the current Judge API by default.

Configuration example

codescoring:
  url: https://codescoring.example.com
  token: "<token>"
  work-mode: strict_wait
  osa-proxy-url: https://osa-proxy.example.com
  enable-status-line: true
  block-on-codescoring-errors: true
  remove-blocked-versions: true
  legacy-judge: false
  stage: proxy
  block-status-code: 403
  judge-concurrency: 10
  resilience:
    retry:
      max-attempts: 3
      wait-duration: 1s
      exponential-backoff-multiplier: 2
    circuit-breaker:
      failure-rate-threshold: 50
      minimum-number-of-calls: 10
      sliding-window-size: 20
      wait-duration-in-open-state: 30s
      permitted-number-of-calls-in-half-open-state: 5

http:
  server:
    read-timeout: 2m
    read-header-timeout: 5s
    idle-timeout: 120s
    shutdown-timeout: 10s
  client:
    connection-timeout: 10s
    response-timeout: 30s
    max-manifest-body-size: 200mb
    max-idle-conns: 100
    max-idle-conns-per-host: 10
    idle-conn-timeout: 90s

pypi:
  enabled: true
  repository:
    - name: pypi
      registry: https://pypi.org
      packages-registry: https://files.pythonhosted.org
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true
    - name: pytorch-pypi
      registry: https://download.pytorch.org
      packages-registry: https://download.pytorch.org
      additional-packages-registries:
        download.pytorch.org: https://download.pytorch.org
        download-r2.pytorch.org: https://download-r2.pytorch.org
        files.pythonhosted.org: https://files.pythonhosted.org
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

maven:
  enabled: true
  repository:
    - name: maven
      registry: https://repo1.maven.org/maven2
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

nuget:
  enabled: true
  repository:
    - name: nuget
      registry: https://api.nuget.org
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

npm:
  enabled: true
  repository:
    - name: npm
      registry: https://registry.npmjs.org
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

composer:
  enabled: true
  repository:
    - name: composer
      registry: https://repo.packagist.org
      packages-registry: https://api.github.com
      additional-packages-registries:
        github.com: https://github.com
        gitlab.com: https://gitlab.com
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

ruby:
  enabled: true
  repository:
    - name: ruby
      registry: https://rubygems.org
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

go:
  enabled: true
  repository:
    - name: go
      registry: https://proxy.golang.org
      sumdb-registry: https://sum.golang.org
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

debian:
  enabled: true
  repository:
    - name: debian
      registry: https://deb.debian.org/debian
      distro: bookworm
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

alpine:
  enabled: true
  repository:
    - name: alpine
      registry: https://dl-cdn.alpinelinux.org/alpine
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

rpm:
  enabled: true
  repository:
    - name: rpm
      registry: https://mirror.stream.centos.org/10-stream/AppStream/x86_64/os
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

docker:
  enabled: true
  repository:
    - name: docker
      registry: https://registry-1.docker.io
      auth-token-url: https://auth.docker.io
      work-mode: strict_wait

cache:
  judge:
    enabled: false
    ttl: 24h
    refresh-after: 30m
    proactive-refresh-enabled: false
    proactive-refresh-interval: 2h
    proactive-refresh-workers: 10
    key-prefix: "cs:judge:"
  redis:
    address: redis:6379
    password: ""
    db: 0

logging:
  level: info

codescoring section

ParameterPurpose
urlCodeScoring platform URL.
tokenCodeScoring access token.
work-modeGlobal work mode when it is not overridden at repository level.
osa-proxy-urlExternal OSA Proxy URL used when building links and responses.
enable-status-lineAdds the block reason to the HTTP/1.1 status line when the client displays it.
block-on-codescoring-errorsBlocks downloads on CodeScoring errors or scan errors.
remove-blocked-versionsRemoves blocked versions from manifests. If false, versions remain marked as blocked where the format supports it.
block-status-codeHTTP status code for blocked downloads. The default is 403.
judge-concurrencyNumber of parallel Judge requests. Used to limit load on Judge when checking large version lists and during background cache refresh.
resilience.retryRetry settings for CodeScoring requests.
resilience.circuit-breakerCircuit breaker settings for temporary degradation of external calls.

Package manager sections

Each ecosystem contains the enabled flag and a repository list. The repository name becomes part of the OSA Proxy URL:

npm:
  enabled: true
  repository:
    - name: company-npm
      registry: https://registry.npmjs.org
      scan-manifest: true
      scan-package: true
      work-mode: strict_wait
      url-encoded-config: true

This repository is available at:

https://osa-proxy.example.com/company-npm/

The scan-manifest and scan-package fields enable checks for manifests and downloaded artifacts. Support for these modes depends on the ecosystem; see Supported protocols. Repository-level work-mode overrides global codescoring.work-mode.

Ecosystem-specific options

composer and pypi support packages-registry and additional-packages-registries when artifacts are downloaded from separate hosts. go uses sumdb-registry when SumDB proxying is required. Docker uses auth-token-url.

Verdict cache

Redis cache is disabled by default:

cache:
  judge:
    enabled: false
  redis:
    address: redis:6379

To enable caching:

cache:
  judge:
    enabled: true
    ttl: 24h
    refresh-after: 30m
    proactive-refresh-enabled: false
    proactive-refresh-interval: 2h
    proactive-refresh-workers: 10
    key-prefix: "cs:judge:"
  redis:
    address: redis:6379
    password: ""
    db: 0

Logging

The log level is configured with logging.level. Supported values are debug, info, warn, and error.

logging:
  level: info

Parameter reference

Root sections

ParameterPurpose
pypiPyPI repository settings.
mavenMaven repository settings.
nugetNuGet repository settings.
npmnpm repository settings.
composerComposer/Packagist repository settings.
rubyRubyGems repository settings.
goGo module proxy settings.
debianDebian repository settings.
alpineAlpine APK repository settings.
rpmRPM/YUM/DNF repository settings.
dockerDocker Registry API v2 settings.
codescoringCodeScoring connection and check behavior.
httpHTTP server and HTTP client timeouts and limits.
cacheRedis Judge verdict cache.
loggingService log level.

Common package manager parameters

ParameterAvailable inPurpose
enabledAll package managersRegisters routes for the ecosystem. If false, repositories from this section are not served.
repositoryAll package managersList of upstream repositories for the ecosystem.
repository[*].nameAll package managersRepository name. For non-Docker ecosystems it becomes the first URL segment: /{name}/.... Must be unique among enabled routes.
repository[*].registryAll package managersUpstream registry URL where OSA Proxy proxies requests.
repository[*].work-modeAll package managersWork mode for a specific repository. If empty, codescoring.work-mode is used.
repository[*].scan-manifestnpm, composer, maven, nuget, pypi, ruby, goEnables manifest/metadata checking and modification.
repository[*].scan-packageAll except dockerEnables checks for downloaded package files. For docker, image checks are handled by Docker Registry proxy logic.
repository[*].url-encoded-configAll except dockerEnables URL-safe Base64 context in the path for Nexus/JFrog scenarios and repository-context policy application.
repository[*].file-type-filterAll except dockerLimits which files are sent to package scanning by extension. If the parameter is omitted or disabled, filtering is not applied.

Repository-specific parameters

ParameterAvailable inPurpose
packages-registrypypi, composerBase URL of a separate host used to download package files when it differs from the metadata registry.
additional-packages-registriespypi, composerAdditional host -> registry map for packages that publish artifacts on multiple domains. Useful for correct routing of external package hosts.
sumdb-registrygoGo checksum database URL, for example https://sum.golang.org, when SumDB requests should go through OSA Proxy.
distrodebian, alpineDistribution or branch name used when processing metadata and package paths.
auth-token-urldockerDocker Registry token service URL. For Docker Hub this is usually https://auth.docker.io; for JFrog/Nexus use the corresponding repository manager endpoint.

file-type-filter

ParameterPurpose
additional-allowed-extensionsYAML array of strings. The presence of this field enables the filter: after that, only extensions from the built-in preset and from additional-allowed-extensions pass, while other unknown extensions are blocked. Values can be written with or without the leading dot; they are normalized to lowercase and to the dotted form.
scanned-extensionsYAML array of strings. Enables the filter and makes the handler treat files with these extensions as package artifacts for scanning and short-lived scan-result caching. Values can be written with or without the leading dot.

The filter applies only to non-Docker repositories. If the file-type-filter section is omitted or set to {}, the filter is disabled: OSA Proxy behaves as if the filter did not exist, so requests follow the normal handler rules and compatibility with previous behavior is preserved. To enable the filter, add at least one of additional-allowed-extensions / scanned-extensions. The presence of the key is what matters: for example, additional-allowed-extensions: [] enables the filter but does not add extensions beyond the built-in preset.

When the filter is enabled, OSA Proxy:

  • lets metadata/manifest requests pass without extension checks;
  • extracts the filename from the URL path, decodes URL-encoded characters, and compares extensions case-insensitively;
  • allows a file when its extension is included in the built-in ecosystem preset or in additional-allowed-extensions;
  • allows checksum and signature sidecar files (.metadata, .sha256, .sha512, .sha1, .asc, .md5) only when the base artifact is also allowed;
  • immediately blocks all other package file requests before contacting the upstream registry or CodeScoring.

Built-in presets:

EcosystemAllowed extensions
npm.tgz
composer.zip, .tar, .tgz, .tar.gz, .tar.bz2, .tar.xz
pypi.whl, .tar.gz, .tar.bz2, .tar.xz, .zip, .egg
nuget.nupkg, .snupkg
ruby.gem
go.zip
alpine.apk
rpm.rpm, .drpm
debian.deb, .udeb, .dsc, .orig.tar.gz, .orig.tar.xz, .orig.tar.bz2, .debian.tar.gz, .debian.tar.xz, .debian.tar.bz2, .diff.gz
maven.pom, .jar, .war, .ear, .rar, .dar, .zip, .tar.gz, .aar, .apk, .aab, .nar, .hpi, .jpi, .kar, .eba, .sar, .par, .car, .mar, .har, .obr, .module

For Debian, source tarballs matching .orig-*.tar.gz, .orig-*.tar.xz, and .orig-*.tar.bz2 are also allowed.

additional-allowed-extensions only extends the filter allow-list. The presence of this field switches the repository to allow-list mode: OSA Proxy allows the built-in ecosystem extensions and the extensions from additional-allowed-extensions, and blocks all other unknown package file extensions. Use it when a repository contains acceptable files with non-standard extensions and the filter must not block them. This parameter does not make the handler send those files to package scanning: if the ecosystem's default strategy does not treat the extension as scannable, the request continues as normal passthrough. To make a new file type participate in package scanning, also add the extension to scanned-extensions.

scanned-extensions controls the second behavior: files with these extensions are treated as scannable package artifacts even if the ecosystem's default strategy does not recognize them. For these extensions, a short-lived scan-result cache is enabled so related files with the same base name can reuse one verdict. For example, Maven can use scanned-extensions: [.jar, .pom] so demo-1.0.0.jar and demo-1.0.0.pom are grouped by the demo-1.0.0 base name.

Example:

npm:
  enabled: true
  repository:
    - name: npm
      registry: https://registry.npmjs.org
      scan-package: true
      file-type-filter:
        additional-allowed-extensions: [tgz, license]
        scanned-extensions: [tgz]

In this example, .tgz is allowed by the npm preset and participates in package scanning, while .license is additionally allowed by the filter but does not become a scannable artifact.

npm behavior example

Without the file-type-filter section, the filter is disabled. The npm handler follows its standard logic: the package tarball left-pad-1.0.0.tgz is sent to package scanning, while other requests are handled as metadata or passthrough depending on the route.

npm:
  enabled: true
  repository:
    - name: npm
      registry: https://registry.npmjs.org
      scan-package: true

An empty section also keeps the filter disabled:

npm:
  enabled: true
  repository:
    - name: npm
      registry: https://registry.npmjs.org
      scan-package: true
      file-type-filter: {}

To enable the filter without adding new extensions, set an empty list. For npm, only the built-in .tgz preset and sidecar files for allowed artifacts are allowed. A request for left-pad-1.0.0.tgz passes and is checked, while left-pad-1.0.0.exe is blocked before the upstream registry and CodeScoring are contacted.

npm:
  enabled: true
  repository:
    - name: npm
      registry: https://registry.npmjs.org
      scan-package: true
      file-type-filter:
        additional-allowed-extensions: []

To allow a non-standard file without sending it to package scanning, add the extension only to additional-allowed-extensions:

npm:
  enabled: true
  repository:
    - name: npm
      registry: https://registry.npmjs.org
      scan-package: true
      file-type-filter:
        additional-allowed-extensions: [license]

With this configuration, .tgz is scanned as an npm package, .license passes the filter as an allowed file, and .exe is blocked by the filter.

codescoring

ParameterDefaultPurpose
urlRequiredCodeScoring platform URL.
tokenRequiredCodeScoring API access token.
work-modeNot setGlobal work mode: warmup, spectator, moderate, strict, strict_wait.
osa-proxy-urlNot setExternal OSA Proxy URL. Used when generating links and rewriting URLs in responses.
enable-status-linefalseAdds the block reason to the HTTP/1.1 status line. Does not affect HTTP/2 or HTTP/3; Docker clients read the JSON body.
block-on-codescoring-errorsfalseBlocks downloads when CodeScoring returns an error or a package cannot be checked.
remove-blocked-versionstrueRemoves blocked versions from manifests. If false, versions remain in metadata with a block marker when the format supports it.
legacy-judgefalseEnables compatibility with Judge versions before 2026.20.0. Use only for CodeScoring installations with an older Judge service version.
stageNot setStage/context value passed to CodeScoring checks. Usually proxy.
block-status-code403HTTP status code returned for blocked packages.
judge-concurrency10Limits the number of parallel Judge requests. Lower values make OSA Proxy send fewer concurrent requests to Judge when checking large version lists and during background cache refresh. Versions are sent in chunks of up to 900 PURLs, so this parameter becomes visible when a single package has more than 900 versions and the check is split into multiple requests.
resilienceSee belowResilience settings for CodeScoring requests.

codescoring.resilience.retry

ParameterDefaultPurpose
max-attempts3Maximum number of request attempts.
wait-duration1sDelay between attempts.
exponential-backoff-multiplier2Exponential backoff multiplier for increasing retry delays.

codescoring.resilience.circuit-breaker

ParameterDefaultPurpose
failure-rate-threshold50Error percentage that opens the circuit breaker.
minimum-number-of-calls10Minimum number of calls required to calculate the error rate.
sliding-window-size20Window size used for error statistics.
wait-duration-in-open-state30sTime before moving from open to half-open state.
permitted-number-of-calls-in-half-open-state5Number of trial requests allowed in half-open state.

http.server

ParameterDefaultPurpose
read-timeout2mMaximum time for reading the whole incoming request.
read-header-timeout5sMaximum time for reading HTTP headers.
idle-timeout120sTime to keep an idle keep-alive connection.
shutdown-timeout10sGraceful shutdown timeout.

http.client

ParameterDefaultPurpose
connection-timeout10sTimeout for establishing connections to upstream registries and CodeScoring.
response-timeout30sResponse wait timeout.
max-manifest-body-size200mbMaximum manifest/metadata response body size the service will process. Values such as 200mb are supported.
max-idle-conns100Maximum number of idle HTTP connections.
max-idle-conns-per-host10Maximum number of idle HTTP connections per host.
idle-conn-timeout90sLifetime of an idle connection in the HTTP client.

cache.judge

ParameterDefaultPurpose
enabledfalseEnables Redis cache for Judge check results.
ttl24hCache entry lifetime.
refresh-after30mEntry age after which it can be refreshed in the background.
proactive-refresh-enabledfalseEnables proactive background refresh for stale entries.
proactive-refresh-interval2hBackground refresh interval.
proactive-refresh-workers10Number of background refresh workers.
key-prefixNot setRedis key prefix, for example cs:judge:.

cache.redis

ParameterPurpose
addressRedis address in host:port format.
passwordRedis password.
dbRedis database number.

logging

ParameterDefaultPurpose
levelinfoLog level: debug, info, warn, warning, error. Unknown values are treated as info.
Was this page helpful?