Skip to content

fix(trust-portal): derive public vendor badges from cert data (CS-688)#3355

Merged
tofikwest merged 2 commits into
mainfrom
tofik/cs-688-trust-public-vendor-badge-derive
Jul 6, 2026
Merged

fix(trust-portal): derive public vendor badges from cert data (CS-688)#3355
tofikwest merged 2 commits into
mainfrom
tofik/cs-688-trust-public-vendor-badge-derive

Conversation

@tofikwest

@tofikwest tofikwest commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Problem

CS-688 was marked Done via #3315/#3318 but the customer reopened it: Scaleway on the public Trust Centre (trust.inc/capawesome) still shows only GDPR, while the admin Vendors tab lists ISO/IEC 27001:2022, HDS and GDPR as verified.

Root cause — the fix landed on the wrong code path

There are two separate paths, and #3315/#3318 only fixed the admin one:

  • Admin (trust-portal.service.ts::getAllVendorsWithSync) — its mapper was corrected and it self-heals the stored Vendor.complianceBadges on read. But that only runs when an admin opens the Vendors page.
  • Public / visitor (trust-access.service.ts::getPublicVendors) — serves the stored complianceBadges verbatim and only re-derives when it's empty. Scaleway's stored value is a stale [gdpr], so it's served as-is. Its fallback mapper (extractBadgesFromRiskData) was also the old brittle exact-match that never recognized "ISO/IEC 27001:2022".

Net: the public portal reads different code than the admin, depends on an admin action that never happened, and can't self-correct. (Also confirmed the visitor fetch is cache: 'no-store', so no caching was hiding a fix, and the admin "Vendors tab" reads the same riskAssessmentData.certifications, so the corrected mapper will map it.)

Fix — one mapper, public path derives live

  • New cert-badge-mapper.ts — single source of truth for cert-name → badge-type, moved verbatim from the tested admin mapper (incl. the bounded matchesIsoStandard that handles the IEC infix and :2022 suffix while rejecting 2701x/unrelated digits).
  • getPublicVendors now derives badges from riskAssessmentData with that shared mapper and treats them as authoritative when present — mirroring the admin sync — falling back to stored badges only when there's nothing to derive. So the two surfaces can no longer disagree.
  • trust-portal.service.ts (admin) now imports the shared mapper instead of its own private copies.

No data backfill required: the public path corrects stale stored badges on the fly, so Scaleway shows ISO 27001 as soon as this deploys — no script, no admin action.

Safety / scope

  • Behavior mirrors the already-in-production admin logic, just applied to the read path; all 7 existing admin regression tests stay green through the shared mapper.
  • Unrecognized certs (e.g. HDS) are dropped consistently with the admin tab — HDS badge support was explicitly out of scope in fix(trust-portal): sync iso 27001 certification mapping with vendor-risk task #3315 and stays out here.
  • The scan-time writers (vendor-risk-assessment-task.ts, trust-portal-deep-scrape-merge.ts) still have their own mappers, but the public path no longer depends on what they persist. Consolidating those is a sensible follow-up, not needed for this fix.

Testing

  • cert-badge-mapper.spec.ts — unit tests: ISO/IEC 27001:2022 → iso27001, 27017/27018 and unrelated-digit guards, verified-only, dedupe, malformed input.
  • trust-access.service.spec.ts — new getPublicVendors regression: a stale [gdpr] stored set + cert data with ISO/IEC 27001:2022 now yields iso27001 + gdpr; plus a no-cert-data case that keeps stored badges.
  • npx jest src/trust-portal → 31 passing. Typecheck clean for changed files (repo main has unrelated pre-existing typecheck errors).

Fixes CS-688

🤖 Generated with Claude Code


Summary by cubic

Fixes CS-688 by making the public Trust Centre derive vendor badges from verified certification data, aligning with the admin view and correcting stale displays (e.g., Scaleway). Adds shared mapping with ISO 27001 and spelled‑out PCI DSS support.

  • Bug Fixes
    • Added cert-badge-mapper.ts as a shared source for cert-name → badge-type (handles ISO/IEC 27001:2022 and maps spelled‑out “Payment Card Industry Data Security Standard” to pci_dss); removed duplicate mappers and dead, separator-specific branches after normalization.
    • getPublicVendors now prefers badges derived from riskAssessmentData and falls back to stored badges only when none are derivable, preventing admin/public mismatches.
    • Admin sync now imports the shared mapper; tests cover the mapper (ISO boundaries, PCI spelled‑out) and a getPublicVendors regression; no data backfill required.

Written for commit 839d4ab. Summary will update on new commits.

Review in cubic

The public Trust Centre subprocessor badges are served by
TrustAccessService.getPublicVendors, which returned the stored
Vendor.complianceBadges verbatim and only re-derived from certification data
when that stored value was empty. Its fallback mapper also used a brittle
exact-match that never recognized "ISO/IEC 27001:2022". So a vendor with a stale
stored badge set (Scaleway: GDPR only) kept showing the wrong badges publicly
even after the admin-side mapper was fixed in #3315/#3318 — the two surfaces ran
different code.

- Add cert-badge-mapper.ts as the single source of truth for turning
  certification names into badge types (moved verbatim from the tested admin
  mapper, incl. the bounded matchesIsoStandard logic).
- getPublicVendors now derives badges from riskAssessmentData with that shared
  mapper and treats them as authoritative when present, mirroring the admin
  sync, so admin and public can no longer disagree. Falls back to stored badges
  only when there is nothing to derive. No data backfill needed — the public
  path corrects stale stored badges on the fly.
- trust-portal.service.ts (admin sync) now imports the shared mapper instead of
  its own private copies.

Tests: shared-mapper unit tests (ISO/IEC 27001:2022, 2701x boundaries,
unrelated-digit guards) + a getPublicVendors regression proving a stale
GDPR-only stored set still yields ISO 27001 from cert data.

Fixes CS-688

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RgkStnwws7zZL39mJ79PeN
@linear

linear Bot commented Jul 6, 2026

Copy link
Copy Markdown

CS-688

@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comp-framework-editor Ready Ready Preview, Comment Jul 6, 2026 6:04pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
app Skipped Skipped Jul 6, 2026 6:04pm
portal Skipped Skipped Jul 6, 2026 6:04pm

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 5 files

Confidence score: 3/5

  • In apps/api/src/trust-portal/cert-badge-mapper.ts, the badge derivation no longer recognizes PCI DSS certificates stored as “Payment Card Industry Data Security Standard,” which can hide verified PCI badges in public/admin views after merge — restore or preserve the existing paymentcard matching path before merging.
  • In apps/api/src/trust-portal/cert-badge-mapper.ts, separator-specific match branches are currently unreachable after normalization strips spaces/underscores, which increases maintenance risk and can mislead future edits — either remove dead branches or run separator-aware checks against a raw lowercased input.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Linked issue analysis

Linked issue: CS-688: [Bug] Trust Centre subprocessor badge mismatch - Scaleway missing ISO 27001 badge

Status Acceptance criteria Notes
Public Trust Centre (getPublicVendors) derives compliance badges from vendor riskAssessmentData and prefers derived badges over stored complianceBadges so the public view matches admin trust-access.service.ts now calls the shared extractComplianceBadges and prefers derivedBadges when present; previous fallback-only behavior was removed.
ISO/IEC 27001 (e.g. "ISO/IEC 27001:2022") is recognized and mapped to the iso27001 badge type (handles IEC infix and year suffix) New cert-badge-mapper implements matchesIsoStandard and mapCertificationToBadgeType; unit test verifies ISO/IEC 27001:2022 → iso27001.
Admin Vendors path uses the same shared mapper so admin and public surfaces cannot disagree trust-portal.service.ts was updated to import and use extractComplianceBadges instead of its previous private mapper.
Regression verified: a vendor with a stale stored badge set (GDPR only) plus verified certs including ISO/IEC 27001 now yields iso27001 + gdpr in the public output A targeted regression test in trust-access.service.spec.ts asserts the public vendors result contains iso27001 and gdpr when globalVendors.riskAssessmentData includes ISO/IEC 27001:2022 and stored complianceBadges only had gdpr.

Comment thread apps/api/src/trust-portal/cert-badge-mapper.ts Outdated
Comment thread apps/api/src/trust-portal/cert-badge-mapper.ts Outdated
…ranches

Address cubic review on the shared cert-badge-mapper:
- Map "Payment Card Industry Data Security Standard" to pci_dss via a
  `paymentcard` substring check, matching the scan-time mappers. Since the
  public path now derives badges authoritatively, without this it would drop a
  PCI badge the scan writer recognizes.
- Remove separator-specific branches ('soc 2', 'pci dss', 'pci_dss', 'nen 7510')
  that were unreachable after normalization strips spaces/underscores; document
  the normalization so the intent is clear. Behavior-preserving.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RgkStnwws7zZL39mJ79PeN
@tofikwest

Copy link
Copy Markdown
Contributor Author

Addressed both cubic findings in 839d4ab:

  • P2 (PCI DSS formal name): Valid gap. The paymentcard match never existed in the display mappers, but it does in the scan-time mappers (vendor-risk-assessment-task.ts, trust-portal-deep-scrape-merge.ts). Since the public path now derives badges authoritatively, a cert named "Payment Card Industry Data Security Standard" would have been dropped even though the scan writer recognizes it. Added normalized.includes('paymentcard') to the shared mapper (pci_dss is an existing badge type, so no new UI type introduced) + a unit test.
  • P3 (dead branches): Correct — after replace(/[^a-z0-9]/g,'') strips spaces/underscores, 'soc 2'/'pci dss'/'pci_dss'/'nen 7510' were unreachable (inherited verbatim from the old admin mapper). Removed them and documented the normalization.

32 tests passing; typecheck clean for changed files.

@tofikwest

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review it

@cubic-dev-ai

cubic-dev-ai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review it

@tofikwest I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cubic analysis

No issues found across 5 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Linked issue analysis

Linked issue: CS-688: [Bug] Trust Centre subprocessor badge mismatch - Scaleway missing ISO 27001 badge

Status Acceptance criteria Notes
Public Trust Centre (getPublicVendors) derives compliance badges from vendor riskAssessmentData and prefers derived badges over stored complianceBadges so the public view matches admin trust-access.service.ts now calls the shared extractComplianceBadges and prefers derivedBadges when present; previous fallback-only behavior was removed.
ISO/IEC 27001 (e.g. "ISO/IEC 27001:2022") is recognized and mapped to the iso27001 badge type (handles IEC infix and year suffix) New cert-badge-mapper implements matchesIsoStandard and mapCertificationToBadgeType; unit test verifies ISO/IEC 27001:2022 → iso27001.
Admin Vendors path uses the same shared mapper so admin and public surfaces cannot disagree trust-portal.service.ts was updated to import and use extractComplianceBadges instead of its previous private mapper.
Regression verified: a vendor with a stale stored badge set (GDPR only) plus verified certs including ISO/IEC 27001 now yields iso27001 + gdpr in the public output A targeted regression test in trust-access.service.spec.ts asserts the public vendors result contains iso27001 and gdpr when globalVendors.riskAssessmentData includes ISO/IEC 27001:2022 and stored complianceBadges only had gdpr.

Re-trigger cubic

@tofikwest tofikwest merged commit dd2ea84 into main Jul 6, 2026
11 checks passed
@tofikwest tofikwest deleted the tofik/cs-688-trust-public-vendor-badge-derive branch July 6, 2026 18:12
claudfuen pushed a commit that referenced this pull request Jul 6, 2026
# [3.98.0](v3.97.0...v3.98.0) (2026-07-06)

### Bug Fixes

* address follow-up ([70c393c](70c393c))
* **api:** add isActive filter to member query ([545bc74](545bc74))
* **api:** tie trust portal access link expiry to the grant duration ([cc493f0](cc493f0))
* **app:** sort assignee list alphabetically in assignee dropdown ([13aa3ef](13aa3ef))
* **cloud-security:** exclude per-task runs from latest scan selection ([c51b17c](c51b17c))
* **risk-treatment:** ensure live tasks filter before ranking in draft plan ([98401f4](98401f4))
* **risk-treatment:** harden orphan task-vector prune (CS-681 review) ([eb3c097](eb3c097))
* **trust-portal:** derive public vendor badges from cert data (CS-688) ([#3355](#3355)) ([dd2ea84](dd2ea84)), closes [3315/#3318](#3318)
* **trust-portal:** restore soc3/pipeda/ccpa badge mappings (CS-688) ([#3357](#3357)) ([e8cb123](e8cb123))
* **trust:** address cubic review on the questionnaire toggle ([6e71c3f](6e71c3f))

### Features

* **trust:** add setting to show/hide the Security Questionnaire on the public trust portal ([f89c323](f89c323))
@claudfuen

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.98.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants