Skip to content

Modernize Contrast Security Assess hook: support file-based VCAP_SERVICES; support token auth - #968

Open
y-myro wants to merge 4 commits into
cloudfoundry:masterfrom
y-myro:hooks/contrastsecurity_modernize
Open

y-myro wants to merge 4 commits into
cloudfoundry:masterfrom
y-myro:hooks/contrastsecurity_modernize

Conversation

@y-myro

@y-myro y-myro commented Oct 14, 2026

Copy link
Copy Markdown

A short explanation of the proposed change

This PR extends the Contrast Security Assess hook (src/nodejs/hooks/contrast_security.go) with four improvements, each in its own commit:

  1. Correctness fixes - credential extraction returned the wrong service when a non-Contrast user-provided service appeared before the Contrast one in the same category; type assertions panicked on malformed VCAP_SERVICES bindings; credential values were written into shell exports without quoting (here I reused the quoting approach from the BOSH CLI).
  2. URL normalization - the /Contrast suffix was appended unconditionally; if teamserver_url already included it (which is the case when you copy it from the UI) the resulting CONTRAST__API__URL was malformed.
  3. Token authentication - the hook now reads api_token from the service binding and writes CONTRAST__API__TOKEN. When both token and legacy credentials are present, all vars are emitted and the agent applies its own precedence.
  4. File-based VCAP_SERVICES - when CF module is configured with file-based-vcap-services, bindings arrive via VCAP_SERVICES_FILE_PATH rather than the env var. The hook now checks that path first and falls back to the env var.

An explanation of the use cases your change solves

  • Users whose service tiles already include /Contrast in teamserver_url were getting a double-suffixed URL, causing agent connection failures.
  • Users using the newer token-based Contrast credentials (a single api_token instead of four separate fields) had no way to configure the agent through the buildpack and had to decode the token first to extract the individual fields.
  • Applications deployed on CF environments with file-based-vcap-services enabled received no Contrast configuration because the hook only checked VCAP_SERVICES.

Checks

  • I have viewed signed and have submitted the Contributor License Agreement
  • I have made this pull request to the master branch
  • I have added an integration test;
    • unit tests added for all four changes;
    • integration test extended with token scenario
    • Also, tested the token-based auth and file-based VCAP_SERVICES scenarios live on my trial BTP CF environment.

… prevent panics and shell injection on malformed VCAP_SERVICES

Three related correctness issues in the Contrast Security hook:

1. Service credential extraction operated on the first entry in a category, not on the entry that actually matched "contrast-security". When a non-Contrast user-provided service appeared before the Contrast one in the same category, the wrong credentials would be returned. Fixed by replacing the two-pass category+loop approach with a single per-service loop.

2. Add basic shell escaping for credential values interpolated into `export` statements.

3. Use the comma-ok idiom to prevent panic if VCAP_SERVICES binding contains unexpected types.
Contrast teamserver displays the Contrast Agent URL with the /Contrast suffix by default nowadays.
The hook unconditionally appended /Contrast/ to the teamserver_url from the service binding. If the URL already included that path, the resulting CONTRAST__API__URL would be malformed.
The URL is now normalised: trailing slashes are stripped, then /Contrast is appended only if not already present. The trailing slash is dropped as it is not required by the agent.
…I__TOKEN)

The Contrast Node.js agent supports a newer API token that encodes all connection details (url, api_key, service_key, user_name) as a single base64 value. Previously only the legacy credential fields were read from VCAP_SERVICES and written to profile.d.

Changes:
- Add ApiToken field to ContrastSecurityCredentials; populated from the api_token key in the service binding credentials block.
- Introduce writeExport() helper that omits a line entirely when the value is empty, replacing the previous unconditional string concat.
- URL, API_KEY, SERVICE_KEY, and USER_NAME are only written when present; CONTRAST__API__TOKEN is written when api_token is present.
- When both legacy credentials and api_token are provided, all vars are written and the agent applies its own precedence (legacy wins).
Cloud Foundry can deliver service bindings via a file instead of the VCAP_SERVICES environment variable when file-based VCAP services is enabled. In that mode VCAP_SERVICES is absent and VCAP_SERVICES_FILE_PATH points to a file with the same JSON structure.

A new loadVcapServicesJSON() method checks VCAP_SERVICES_FILE_PATH first and falls back to the VCAP_SERVICES env var. When both are set, the file path takes precedence (it was explicitly enabled as a feature) and a warning is logged.
@linux-foundation-easycla

linux-foundation-easycla Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant