---
id: TST-PFM-SEC-227
title: Workspace hubspot link request checks
kind: api-lifecycle
product_area: platform
module: security
revision: 2
status: draft
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
repository: services-platform
files:
  - modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js
implements:
  - ATS-PFM-SEC-002-07
environment: local
implementation_state: implemented
latest_result: not-run
latest_run_at: null
latest_run_ref: null
conformance: not-verified
estimated_minutes: 5
isolation: Use the prepared test database and suite-owned fixture rows; retain shared seed records.
assertion_evidence:
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#the HubSpot
      company link on the tenants API (end to end)
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#creating a tenant
      without saying anything about a company
  - provenance: test
    source: 'services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#answers 200'
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#links the tenant
      to the company of the customer that pays for it
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#creating a tenant
      that names its own company
  - provenance: test
    source: 'services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#answers 200'
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#stores the company
      the body named, in place of the customer’s
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#creating a tenant
      that says it has no company
  - provenance: test
    source: 'services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#answers 200'
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#answers a tenant
      under the customer that has a company
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#leaves the tenant
      with no company, rather than taking the customer’s
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#the record writes,
      which no longer carry the link
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a patch
      that moves the link as 400, even for Rhythm staff in their own editor
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#names the route
      that does move the link in that refusal
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses an
      administrator of the customer the same way, because the body is wrong rather than the caller
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a patch
      that clears the link as well
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a
      replacement that simply drops the field, because omitting it would clear the link
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#accepts a
      replacement that sends the company back unchanged, as a round trip of a record just read does
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#leaves the link on
      the company of the customer after those refusals
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#lets an
      administrator of the customer change a field that is theirs, so the refusals are about this
      one
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#moving the link
      with PUT /tenants/{id}/hubspot_company
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#answers 200 to
      Rhythm staff
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#answers the tenant
      with the company staff named, at the next version
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#leaves the rest of
      the tenant where it was
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#persists the move,
      read back through the API
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a second
      move at the version already written as 409
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses an
      administrator of the customer as 403, because this is a system route
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses that
      administrator clearing the link as well
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses an
      anonymous call as 401
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a body
      with no hubspot_company_id as 400, because leaving the field out is not the same as clearing
      it
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses a body
      with no version as 400, as every other staff write of this module does
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#refuses an unknown
      tenant as 404
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#leaves the link
      where staff put it after those refusals
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#clearing the link
      with PUT /tenants/{id}/hubspot_company
  - provenance: test
    source: 'services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#answers 200'
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#starts from a
      tenant that holds the company of its customer, so the clearing is what is proved
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#answers a tenant
      with no company at all
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#persists the
      clearing, so the tenant does not take its customer’s company back
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#the licence sync
      the move asks for
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#asks for the
      company it moved the tenant to to be read from HubSpot
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#says the link is
      what asked for it, which is what an operator reads in a log
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#asks for nothing
      when the link is cleared, because there is no company to read
  - provenance: test
    source: >-
      services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js#asks for nothing
      when the move is refused, so a refused write causes no read
dependency_evidence: >-
  The local request harness exercises the route dispatcher and the prepared database. The suite
  controls workflow execution, remote service participants, the signing key at the declared seams;
  those collaborators remain outside its live proof.
evidence:
  - 'services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js'
  - >-
    Static review at the recorded source revision; executable results remain not-run and conformance
    remains not-verified.
binding_note: >-
  Each binding names the scenario to which this file contributes assertions. A binding is not a
  recorded pass and does not extend the file’s dependency boundary.
examiner: codex
examined_at: '2026-10-23'
final_text: OpenAI
dependency_review:
  provenance: test
  source: 'services-platform:modules/tenants/tests/e2e/tenant-hubspot-link.e2e.spec.js'
  explicit_no_doubles: false
  identified_double_boundaries:
    - workflow execution
    - remote service participants
    - the signing key
---
# Workspace hubspot link request checks

## Verification Boundary

The file exercises public request handling through the local service harness. The assertion references identify the source checks for workspace hubspot link.

## What This Suite Proves

The source assertions support the observations named in the bound scenarios. A scenario spanning multiple files must retain the other files’ contributions.

## What It Does Not Prove

This examination does not run the suite. Passing behavior, deployed conformance and the behavior of substituted dependencies require separate execution evidence.

## Real Dependencies and Test Doubles

The local request harness exercises the route dispatcher and the prepared database. The suite controls workflow execution, remote service participants, the signing key at the declared seams; those collaborators remain outside its live proof.

## Must Not Be Doubled

Keep route dispatch, signed-context verification and the exercised service decisions real. A test key can supply signatures, but replacing the authorization decision cannot prove request enforcement.
