From e3ace23703c9c35cbd9fc6e01c395b6ddc2309c0 Mon Sep 17 00:00:00 2001 From: ustaxs Date: Sat, 17 Oct 2026 19:56:45 +0100 Subject: [PATCH] docs: add erasure, consent, vendor risk, and retention policies Add four data-protection policies under Governance/policies/ covering the lifecycle of personal data from collection to disposal: - DATA_DELETION.md: how a request is received and verified, timelines from receipt, execution order across stores and subprocessors, a verification requirement, and refusal rules. - CONSENT_MANAGEMENT.md: what requires consent, conditions for a valid request, how consent is recorded, how it is withdrawn, and re-consent on a change of purpose. - VENDOR_RISK.md: vetting criteria with required evidence, four risk tiers, review cadence per tier, and exit planning. - RECORD_RETENTION.md: a retention schedule where every entry names its trigger, disposal methods, and a legal-hold process with 90-day review. Three positions recur across the set: a promise the project cannot evidence is worse than no promise, so each document defines how compliance is verified; identity is verified before deletion, since deleting on an unverified request is a denial-of-service against a real account; and retention periods are checked for shortening at review, because schedules drift longer when nobody reduces one. Closes #1497 Closes #1498 Closes #1499 Closes #1500 --- Governance/policies/CONSENT_MANAGEMENT.md | 191 ++++++++++++++++++++ Governance/policies/DATA_DELETION.md | 206 ++++++++++++++++++++++ Governance/policies/RECORD_RETENTION.md | 180 +++++++++++++++++++ Governance/policies/VENDOR_RISK.md | 183 +++++++++++++++++++ 4 files changed, 760 insertions(+) create mode 100644 Governance/policies/CONSENT_MANAGEMENT.md create mode 100644 Governance/policies/DATA_DELETION.md create mode 100644 Governance/policies/RECORD_RETENTION.md create mode 100644 Governance/policies/VENDOR_RISK.md diff --git a/Governance/policies/CONSENT_MANAGEMENT.md b/Governance/policies/CONSENT_MANAGEMENT.md new file mode 100644 index 0000000..9c09595 --- /dev/null +++ b/Governance/policies/CONSENT_MANAGEMENT.md @@ -0,0 +1,191 @@ +# Consent Management Policy + +## Purpose + +This policy defines what requires the user's consent, how consent is asked for and +recorded, how it is withdrawn, and what the app does when consent is absent. Consent is +easy to implement badly: a banner that appears once and is never revisited, a checkbox +pre-ticked, a withdrawal path that does not exist. This document makes each of those a +named failure. + +## Scope + +This policy covers consent for anything TeachLink Mobile does that is not strictly +necessary for the app to function, and it covers the collection and use of personal data +where the lawful basis is consent. + +It covers: + +- what is asked for, in the app and in the store listing; +- the wording, granularity, and presentation of each request; +- how consent is recorded and evidenced; +- how consent is withdrawn, and what happens then; +- consent obtained from a parent or guardian for a child; and +- how a change to what is consented to is handled. + +It does not define what data is collected, which is the +[Privacy Manifest Policy](../domains/PRIVACY_MANIFEST.md), nor the telemetry rules, which +are the [Mobile Telemetry Governance](../domains/MOBILE_TELEMETRY.md). Where those +documents state a requirement, this policy states the mechanism for obtaining it. + +## What Requires Consent + +| Processing activity | Consent required | Notes | +| --- | --- | --- | +| Essential processing: authentication, account, core lesson delivery, payments | **No** | Necessary to provide the service; covered by the contract and the privacy policy rather than an in-app consent prompt | +| Analytics and product telemetry | **Yes**, opt-in | Must be off until consent is given; see [Mobile Telemetry Governance](../domains/MOBILE_TELEMETRY.md) | +| Crash reporting with personal data | **Yes** | Where the data would otherwise contain personal data, consent is required or the data is scrubbed | +| Push notifications | **Yes**, per category | Notification categories are consented to separately; consent for one does not imply another | +| Biometric authentication | **Yes**, explicit | Enabled only after the user turns it on, per the [Biometric Authentication Policy](../domains/BIOMETRIC_AUTH.md) | +| Optional device permissions | **Yes** | Requested in context, with the app's core function working if refused, per the [Mobile Permissions Policy](../domains/MOBILE_PERMISSIONS.md) | +| Personalisation that requires profiling | **Yes** | Must be separately consentable from analytics | +| Sharing data with a third party beyond the service providers | **Yes** | Each distinct recipient or purpose is a separate consent | +| Data processed in a new region or for a new purpose | **Yes**, renewed | A purpose change requires fresh consent, not the original consent extended | +| Research or analytics use of de-identified data | **Yes**, where the law requires it | Where the data is genuinely irreversible, the basis may be elsewhere; the choice is recorded | + +Two rules govern the whole table: + +- **Necessary processing is not disguised as consent.** A prompt that asks for something + the app cannot work without is not consent, and presenting it as one is misleading. +- **Consent is per purpose, not per product.** "Yes, I agree to analytics" does not + cover notifications, sharing, or a new purpose. Bundled consent is treated as invalid + in this policy. + +## How Consent Is Requested + +A valid request meets all of these conditions. + +| Condition | Requirement | +| --- | --- | +| Purpose stated plainly | The prompt says what data is used for, in the user's terms, not in the vendor's | +| Freely given | Refusing has no penalty. A refusal does not block the core app, reduce functionality, or degrade the experience for unrelated features | +| Unbundled | Each purpose is requested separately, not as one "Accept all" with no granular choice | +| Not pre-selected | The opt-in control starts off. A pre-ticked box, or a consent implied by not declining within a countdown, is not consent | +| Granular where it matters | Notification categories, analytics, and sharing are separable | +| Explicit action required | Consent follows an affirmative action, never the mere absence of objection | +| Accessible | Presented in a form a screen reader and a translator can handle, with alternatives to the prompt itself | +| Non-disruptive | Repeated requests for the same consent are not allowed; declining is remembered and not re-asked on every launch | +| Equal prominence | Accept and decline are visually comparable; a decline option is not hidden behind a link | + +A prompt that fails any of these is changed rather than defended. In particular, a +"continue without accepting" path is never presented as the default or the recommended +option. + +## How Consent Is Recorded + +| Element | Requirement | +| --- | --- | +| Record content | Who consented, for which purpose, the wording version shown, the timestamp, and the mechanism used | +| Granularity | One record per purpose, so withdrawal of one purpose does not remove the others | +| Evidence | The record must show what the user actually saw, not merely that they agreed | +| Storage | Held in a controlled store with restricted access, per the [Encryption Policy](ENCRYPTION.md), and covered by the [Access Register](../registers/ACCESS_REGISTER.md) | +| Retention | Retained while the consent is relied on and for a defined period afterwards as evidence, per the [Record Retention and Legal Hold Policy](RECORD_RETENTION.md) | +| Children | Recorded against the parent or guardian who gave it, linked to the child's account per the [Children's Data Policy](../compliance/CHILDRENS_DATA.md) | +| Account transfer | A consent record does not transfer to a new account owner or a merged account; it is re-obtained | +| Access to records | A user may ask what is recorded and receives it, subject to the privacy rules in the [Privacy Policy Governance](../compliance/PRIVACY_POLICY_GOVERNANCE.md) | + +Where consent cannot be evidenced, the project does not rely on it. An unrecorded +consent is treated as absent, and the activity stops. + +## How Consent Is Withdrawn + +Withdrawal must be as easy as giving consent, which for most purposes means inside the +app rather than only by contacting the project. + +| Rule | Requirement | +| --- | --- | +| Access to withdraw | A single, discoverable control in the app's settings, and a written channel outside the app | +| Effect | From withdrawal, the consented activity stops. Data already collected is handled under the [Right-to-Erasure Policy](DATA_DELETION.md) | +| No penalty | Withdrawing does not reduce functionality, block access, or require a reason | +| Scope respected | Withdrawing one purpose leaves the others in place; withdrawing all consent ends the optional processing only, not the account | +| Propagated | Subprocessors are instructed to stop processing, per the [DPA Template](../compliance/DPA_TEMPLATE.md) | +| Confirmed | The app confirms that the withdrawal took effect and states what stopped | +| Essential data | Data necessary to provide the service is not deleted by withdrawing optional consent; the account is closed instead, following the [Right-to-Erasure Policy](DATA_DELETION.md) | + +A user who withdraws consent for analytics and continues using the app is not asked why, +and analytics does not resume on the next update or prompt cycle. + +## Consent for Children + +Consent for a child follows the [Children's Data Policy](../compliance/CHILDRENS_DATA.md), +which this policy does not restate: + +- parental or guardian consent is obtained through the age-appropriate flow the + children's policy defines, verified to the standard that policy requires; +- the child's own assent is sought where the law or the children's policy requires it, + and is recorded separately from the parent's consent; +- a child's consent cannot substitute for a parent's, and a parent's consent is not + evidence of the child's assent; +- when consent cannot be obtained, the optional processing is off rather than assumed; + and +- a change affecting children is reviewed under that policy's change-review process + before it ships. + +## Changing What Is Consented To + +A change to the purposes, the wording, or the recipients covered by an existing consent +requires fresh consent. + +- **Wording changes that narrow the request** continue under the original consent; the + wording version is recorded so the evidence shows what was agreed. +- **Wording changes that broaden the request** require re-consent. Substituting broader + language under an existing consent is not permitted. +- **A new purpose, recipient, or region** requires a new consent prompt, and the old + consent is not reused for it. See the [Data Residency Policy](DATA_RESIDENCY.md) for + the residency position. +- **Re-consent respects the withdrawal.** Someone who declined is not re-prompted by + default; where re-prompting is necessary, it is a one-time prompt that honours a + decline made in the previous cycle. +- **A new privacy policy version** is published before it takes effect, following the + [Privacy Policy Governance](../compliance/PRIVACY_POLICY_GOVERNANCE.md), and the + consent screen is updated to match it in the same release. + +## Enforcement Status + +- Consent behaviour in the app is covered by unit tests for the settings and telemetry + paths and is verified in the Maestro flows in `maestro/`. There is no automated check + that a new screen collecting data adds a consent prompt, so a new feature's consent + requirement depends on review. +- Defaults are enforced by the code that gates telemetry on consent, not by review + alone: an unconsented path sends nothing, per the + [Mobile Telemetry Governance](../domains/MOBILE_TELEMETRY.md). +- The consent record store is a controlled system; its contents are covered by the + [Access Register](../registers/ACCESS_REGISTER.md) review. + +## Exceptions + +An activity that proceeds without consent is an exception, recorded in the +[Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) with the legal basis +relied on, the compensating control, an approver holding the authority to grant it, and +an expiry no more than 12 months ahead. "It improves our metrics" is not a basis. +Where the activity concerns children, the +[Children's Data Policy](../compliance/CHILDRENS_DATA.md) conditions apply and an +exception that conflicts with them cannot be granted. + +## Ownership and Review + +The [Security Officer](../roles/SECURITY_OFFICER.md) owns this policy, with the +[Community Manager](../roles/COMMUNITY_MANAGER.md) accountable for the wording users see +and the [Release Manager](../roles/RELEASE_MANAGER.md) for propagation to subprocessors. +It is reviewed whenever a new purpose, recipient, or SDK is added, and at least once +every 12 months. Changes are proposed in a pull request that touches only the +`Governance/` folder. + +## Related Documentation + +- [Privacy Manifest Policy](../domains/PRIVACY_MANIFEST.md): the single source of truth + for what is collected +- [Mobile Telemetry Governance](../domains/MOBILE_TELEMETRY.md): telemetry consent and + PII exclusion +- [Mobile Permissions Policy](../domains/MOBILE_PERMISSIONS.md) and + [Biometric Authentication Policy](../domains/BIOMETRIC_AUTH.md) +- [Right-to-Erasure Policy](DATA_DELETION.md): deleting data after withdrawal +- [Record Retention and Legal Hold Policy](RECORD_RETENTION.md): how long consent records + are kept +- [Children's Data Policy](../compliance/CHILDRENS_DATA.md): parental consent and age + thresholds +- [Privacy Policy Governance](../compliance/PRIVACY_POLICY_GOVERNANCE.md) and + [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md) +- [Encryption Policy](ENCRYPTION.md) and + [Access Register](../registers/ACCESS_REGISTER.md) +- [Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) diff --git a/Governance/policies/DATA_DELETION.md b/Governance/policies/DATA_DELETION.md new file mode 100644 index 0000000..43daf63 --- /dev/null +++ b/Governance/policies/DATA_DELETION.md @@ -0,0 +1,206 @@ +# Right-to-Erasure Policy + +## Purpose + +This policy defines how a request to delete a person's data is received, verified, +executed, and confirmed, and what happens to data that must be kept instead. A deletion +promise the project cannot evidence is worse than no promise, so this document covers +the verification step as carefully as the deletion step. + +## Scope + +This policy covers any request to erase personal data held by TeachLink Mobile or by a +processor acting on its behalf, whatever the caller calls it — delete my account, remove +my data, right to erasure, right to be forgotten, or a school asking for a student's +records to be removed. + +It covers: + +- data in the primary application database, its replicas, and its backups; +- data held by subprocessors, per the + [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md); +- data cached on a user's device, which is under the user's own control; and +- data that cannot be deleted, and why. + +It does not define how long data is otherwise kept, which is the +[Record Retention and Legal Hold Policy](RECORD_RETENTION.md); what is collected, which +is the [Privacy Manifest Policy](../domains/PRIVACY_MANIFEST.md); or where data is +stored, which is the [Data Residency Policy](DATA_RESIDENCY.md). + +## How a Request Is Received + +| Requester | Accepted through | Identity verification | +| --- | --- | --- | +| The account holder | The in-app deletion flow, or a written request to the address in the privacy policy | Authenticated session, or a response to a challenge sent to the registered contact address | +| A parent or guardian acting for a child | The written request channel, per the [Children's Data Policy](../compliance/CHILDRENS_DATA.md) | Proof of guardianship proportionate to the risk, which may mean direct confirmation with the school | +| An authorised school administrator | The written request channel, naming the learner | Confirmation with the school through an already-established contact, not through the requester alone | +| A regulator or supervisory authority | The written request channel | Verification of authority before any disclosure | + +Rules that apply to every request: + +- **A deletion request is never handled through a public issue, a review comment, or a + public thread.** A request containing personal data is redirected to a private channel + before anything else happens, and anything already posted publicly is treated as a + disclosure. +- **Identity is verified before anything is deleted.** Deleting on an unverified request + is a denial-of-service attack on a real account, and it is harder to detect than + unauthorised access. Where verification is not possible, the project does not delete + and says why. +- **No account identifier is confirmed to an unverified caller.** The response to an + unverified request says only that the request cannot be processed without + verification, not whether the account exists. +- **A verbal or informal request is honoured as a request.** It is not dismissed because + it did not arrive on the right form; the project helps the requester complete the + channel and records when the clock started. + +## Timelines + +The clock starts when a request is received, not when it is fully verified, so that a +slow verification cannot be used to extend the deadline indefinitely. + +| Step | Target | +| --- | --- | +| Acknowledge receipt | **5 business days** | +| Verify identity and scope | **10 business days** | +| Execute deletion across the project and its subprocessors | **20 business days** | +| Confirm completion in writing | **30 business days** from receipt | + +Rules that qualify the timelines: + +- **A partial or staged deletion is still a deletion.** Data that cannot be removed + immediately, such as a backup restored in the ordinary course, is scheduled for + deletion and the schedule is given in the confirmation. +- **Where the law gives a shorter deadline, the shorter deadline applies.** The timeline + above is the project's own commitment and never a way to exceed a statutory period. +- **A request that is refused is answered within the same 30 days**, with the reason and + the route to challenge it. A silent refusal is not an answer. +- **A request that is complex is not automatically slower.** Where scope is unclear, the + project asks one clarifying question and keeps working; it does not treat the question + as a reset of the timeline. +- **Repeat requests do not restart the clock.** They are matched to the open request. + +## Execution + +Deletion is executed in a defined order so that partial completion is detectable. + +1. **Primary store.** Personal data in the primary application database is deleted or + anonymised, following the retention position for each field in the + [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md). +2. **Related and derived data.** Search indexes, caches, analytics properties, support + records, and exports are included. Data derived from the person is deleted or + irreversibly anonymised, since pseudonymised data that can be re-identified is still + personal data. +3. **Subprocessors.** Every processor holding the data is instructed to delete it within + a period no longer than the project's own, and each one is confirmed. A processor + that cannot comply within the window is escalated before the deadline, not after it. + The [DPA Template](../compliance/DPA_TEMPLATE.md) requires this obligation. +4. **Backups and replicas.** Backups are deleted on the documented rotation, or are + allowed to age out, and the project states which. Backup media is not rewritten to + erase one person, because that damages the restore guarantee for everyone; the + position is stated plainly to the requester rather than claimed as complete deletion. +5. **Device data.** Data held only on the user's device — the offline cache, local + storage, and tokens — is deleted by the in-app flow or by uninstalling the app. The + project states this plainly rather than implying it performed the deletion. +6. **Records that must be kept.** Data retained under a legal obligation is not deleted, + is isolated so it cannot be used for any other purpose, and the requester is told + what was retained and why. Retention follows the + [Record Retention and Legal Hold Policy](RECORD_RETENTION.md). + +## Verification + +Deletion is verified before the project says it is done. Confirmation is a claim, and an +unverified claim is a liability waiting for an audit. + +| Verification | How | +| --- | --- | +| The deletion ran | A dated deletion record exists, naming the request, the scope, the systems, and the timestamp | +| The data is gone | The deleted records are queried after deletion and return nothing, for each store in scope | +| Subprocessors confirmed | Each processor's written confirmation is retained with the record, and a non-responder is recorded as an exception rather than assumed compliant | +| Derived data is handled | Anonymisation, where used instead of deletion, is verified as irreversible by re-identification testing, not assumed from the absence of a key column | +| No copy survives in exports | Exports, backups, and caches are checked against the same list of locations the deletion covered | +| The confirmation is accurate | The written confirmation to the requester lists exactly what was deleted, what was retained and why, and what is scheduled for a later date | + +A deletion is not confirmed complete when any part is unknown. Where a subsystem's state +cannot be verified, that fact is stated in the confirmation rather than omitted, and it +becomes a tracked follow-up. + +## Children and Schools + +Requests involving a child follow the +[Children's Data Policy](../compliance/CHILDRENS_DATA.md) in addition to this policy: + +- the parent's or guardian's consent governs the account, and a child's own request is + handled with the guardian's involvement unless the law says otherwise; +- school-held records are deleted at the school's instruction, since the school is the + controller for the educational record; and +- the [Age Thresholds](../compliance/CHILDRENS_DATA.md#age-thresholds) in that policy + determine who may request deletion for a given account. + +## Refusal and Partial Refusal + +A request may be refused or partially refused only for a stated legal reason — for +example, an obligation to retain financial records, or a legal claim. Refusal requires: + +- the specific reason, not a generic reference to policy; +- the data actually retained, and the period it is kept; +- confirmation that the retained data is isolated and used only for the reason given; +- the route to challenge the refusal, through the + [Conflict Resolution Process](../processes/CONFLICT_RESOLUTION.md); and +- a review date, because a refusal is reassessed rather than standing forever. + +Refusing everything on a request is treated as a failure, not a preference. Where only +part of the scope is retained, the rest is deleted and the confirmation says which part +and why. + +## Interaction with Retention and Backups + +Deletion requests do not override a legal hold. Where a hold is in place, the project +tells the requester that the data is being retained under a legal obligation, states the +scope of the hold, and does not delete the held material. The hold itself follows the +[Record Retention and Legal Hold Policy](RECORD_RETENTION.md); erasure resumes when the +hold is released. + +## Enforcement Status + +- The project operates no backend of its own, so these controls are exercised through + the providers recorded in the [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md) + and enforced through the [DPA Template](../compliance/DPA_TEMPLATE.md). +- No automated erasure pipeline or verification harness exists in this repository. The + verification table above is the specification a backend implementation must satisfy. +- The privacy policy must state the erasure channel and timeline; the + [Privacy Policy Governance](../compliance/PRIVACY_POLICY_GOVERNANCE.md) owns that + document and is updated when this policy changes. + +## Exceptions + +A request that cannot be completed within the timeline, or a scope that cannot be +verified, is recorded in the +[Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) with the reason, +the compensating control, an approver holding the authority to grant it, and an expiry +no more than 12 months ahead. The requester is still answered within the timeline; an +exception never removes the obligation to respond. + +## Ownership and Review + +The [Security Officer](../roles/SECURITY_OFFICER.md) owns this policy, with the +[Release Manager](../roles/RELEASE_MANAGER.md) accountable for subprocessor deletion +confirmations. It is reviewed at least every 12 months, and after any failure to honour +a request. Changes are proposed in a pull request that touches only the `Governance/` +folder. + +## Related Documentation + +- [Record Retention and Legal Hold Policy](RECORD_RETENTION.md): how long data is kept + and what a hold suspends +- [Consent Management Policy](CONSENT_MANAGEMENT.md): withdrawing consent +- [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md): what is + processed and on what basis +- [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md) and + [DPA Template](../compliance/DPA_TEMPLATE.md): deletion obligations on processors +- [Children's Data Policy](../compliance/CHILDRENS_DATA.md): requests involving children +- [Privacy Manifest Policy](../domains/PRIVACY_MANIFEST.md) and + [Privacy Policy Governance](../compliance/PRIVACY_POLICY_GOVERNANCE.md) +- [Security Policy](../SECURITY_POLICY.md): reporting a suspected breach instead +- [Conflict Resolution Process](../processes/CONFLICT_RESOLUTION.md): challenging a + refusal +- [Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) diff --git a/Governance/policies/RECORD_RETENTION.md b/Governance/policies/RECORD_RETENTION.md new file mode 100644 index 0000000..abc5e46 --- /dev/null +++ b/Governance/policies/RECORD_RETENTION.md @@ -0,0 +1,180 @@ +# Record Retention and Legal Hold Policy + +## Purpose + +This policy defines how long TeachLink Mobile keeps each category of data, what +triggers its deletion, and how a legal hold suspends deletion for the data it covers. +Keeping data longer than needed is a liability to the people it belongs to; deleting +data too eagerly can destroy records the project is obliged to retain. The resolution is +a written schedule with concrete triggers, not a judgement call per record. + +## Scope + +This policy covers every category of record the project holds, whether in the primary +database, in backups, or with a subprocessor. It covers: + +- account and authentication records; +- student, teacher, and school records; +- lesson content and generated material; +- telemetry, analytics, and crash reports; +- audit and access records; +- financial and billing records; +- consent records, as evidence that consent was given; +- support and correspondence records; +- security and incident records; and +- governance records, which follow the retention conventions in this repository. + +It does not cover how data is deleted on request, which is the +[Right-to-Erasure Policy](DATA_DELETION.md), or how long data is retained by a +subprocessor after the project instructs deletion, which is set by the +[DPA Template](../compliance/DPA_TEMPLATE.md). + +## Retention Schedule + +The schedule records the trigger as well as the period, because a period without a +trigger is unenforceable: a clock that starts when nothing happens is a clock that never +starts. + +| Record category | Retention period | Trigger | Basis | +| --- | --- | --- | --- | +| Account profile data | Duration of the account, then 30 days | Account closure | Necessity of the service | +| Authentication tokens and sessions | Until expiry or logout, then immediately | Session end | Security | +| Student and school records | Duration of the enrolment, then the period below | Enrolment end | Legal or contractual record-keeping | +| Attendance and progress records | **7 years** from the end of the academic year | Academic year end | Statutory education record | +| Lesson content created by a teacher | Duration of the account, then 30 days | Account closure | User's own content | +| Generated and cached content | Duration of the account | Account closure | User's own content | +| Consent records | Duration of the consent plus **3 years** as evidence | Consent withdrawn or superseded | Evidence of lawful basis | +| Support correspondence | **2 years** from closure | Ticket closed | Service quality and dispute handling | +| Security and incident records | **6 years** from closure | Incident closed | Security investigation and accountability | +| Audit and access logs | **1 year**, rolling | Each event | Detection and accountability | +| Telemetry and analytics events | **13 months** | Each event | Product measurement, minimisation | +| Crash reports | **90 days** | Each report | Defect triage | +| Financial and billing records | **7 years** from the transaction | Transaction date | Statutory accounting requirement | +| Consent and privacy request correspondence | **3 years** | Request closed | Evidence of compliance | +| Governance documents and decision records | **Indefinite** | — | Public accountability; kept in the repository itself | +| Released build artifacts and provenance records | For the lifetime of the published release | Release | Reproducibility and incident response | + +Rules that apply across the schedule: + +- **A period is either concrete or it is not a period.** "As long as necessary" and + "for a reasonable period" are not acceptable entries in this schedule. +- **The shortest defensible period is chosen.** Where a basis exists for a longer period + it is named; where it does not, the period is the shorter one. +- **Deletion happens when the trigger fires**, on a defined schedule rather than + opportunistically, so that a record is not kept indefinitely because nobody ran a job. +- **Backups follow the primary.** A backup is deleted on its own rotation or allowed to + age out; the position is stated to anyone who asks under the + [Right-to-Erasure Policy](DATA_DELETION.md), rather than claimed as immediate deletion. +- **Where the law requires longer, the law wins.** A statutory period overrides this + schedule, and the entry is updated to say so rather than being quietly extended. + +## Disposal Rules + +Disposal is deletion, not hiding. Each category has a disposal method chosen for it. + +| Method | Applies to | Notes | +| --- | --- | --- | +| Hard delete from the primary store | Profiles, sessions, tokens, message content | Immediate, with index and cache cleanup included | +| Irreversible anonymisation | Aggregate analytics where a record is needed for measurement | Verified irreversible, not merely stripped of an identifier | +| Expiry with a retention window | Telemetry, crash reports, support records | Deleted on the stated cycle | +| Rotate and age out | Backups | Deleted on the backup cycle; not rewritten for one record | +| Retain in full | Statutory records such as attendance and financial entries | Isolated, access-restricted, and used only for the statutory purpose | +| Retain in the repository | Governance documents | Public by design | + +Rules that apply to disposal: + +- **Disposal is verified, not assumed.** A deletion job that has not been observed + removing data is a failure, and is fixed or escalated. +- **Anonymisation is tested.** Data that could be re-identified by joining on another + table is not anonymised. Verification is part of the disposal, not a follow-up. +- **Disposal covers every copy.** Indexes, caches, exports, and subprocessor copies are + included in the category, or the category entry says which are excluded and why. +- **Retention beyond the period requires a basis.** Extending a period is a change to + this schedule, made through the normal governance process, not an operational choice. + +## Legal Hold + +A legal hold suspends deletion for the records it covers, whatever the schedule says. + +1. **A hold is issued by a named role.** Only the [Security Officer](../roles/SECURITY_OFFICER.md) + or a maintainer designated in the [Decision Rights Matrix](../matrices/DECISION_RIGHTS_MATRIX.md) + may issue one, and every hold names the person who issued it. +2. **Scope is explicit.** The hold states the records covered, the matter it relates to, + the date it was issued, and who to ask about its release. A hold with no scope is + invalid. +3. **Effect is immediate.** On issue, scheduled deletion for the covered records is + suspended, including automated jobs and backup rotation for that data. +4. **Covered data is isolated.** Held records are separated from ordinary processing so + they are not used for any other purpose, and access is restricted to those who need + it. +5. **People affected are told where they have a right to know.** A requester whose data + is held is told that it is being retained and why, per the + [Right-to-Erasure Policy](DATA_DELETION.md), unless law forbids disclosure. +6. **Review.** The hold is reviewed every 90 days and released when the matter closes. + A hold that is never released is a defect, not a permanent condition. +7. **Record.** The hold, its scope, its issue and release dates, and the approver are + recorded. Holds are never silently dropped. + +A hold does not authorise new processing of the held data. It preserves what already +exists. + +## Review of the Schedule + +- The schedule is reviewed **every 12 months** by the + [Security Officer](../roles/SECURITY_OFFICER.md) with the maintainers. +- It is reviewed immediately when a legal requirement changes, when a new category of + data is introduced, when a subprocessor changes its retention, or when a + [Right-to-Erasure Policy](DATA_DELETION.md) request cannot be honoured because of a + retention entry. +- The review checks that each period is still the shortest defensible one. Schedules + drift longer because nobody reduces a period, so reducing one is part of the review. +- Every period is checked against the + [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md), and the two are + corrected together. + +## Enforcement Status + +- The project operates no backend, so deletion is executed through the providers + recorded in the [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md), + with obligations set by the [DPA Template](../compliance/DPA_TEMPLATE.md). +- The repository contains no deletion job, and none of the retention periods in this + schedule is machine-enforced. This document is the specification an implementation + must satisfy. +- Where telemetry is in the app's own control, consent gates what is collected at all, + which shortens the problem; see the + [Mobile Telemetry Governance](../domains/MOBILE_TELEMETRY.md) and the + [Consent Management Policy](CONSENT_MANAGEMENT.md). + +## Exceptions + +A category retained beyond its period, or a hold issued without the process above, is +recorded in the +[Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) with the reason, +the compensating control, an approver holding the authority to grant it, and an expiry +no more than 12 months ahead. Where data concerns a child, the +[Children's Data Policy](../compliance/CHILDRENS_DATA.md) applies and minimisation is +required even where a longer period would otherwise be defensible. + +## Ownership and Review + +The [Security Officer](../roles/SECURITY_OFFICER.md) owns this policy, with the +[Release Manager](../roles/RELEASE_MANAGER.md) accountable for subprocessor retention. +It is reviewed every 12 months and after any legal change. Changes are proposed in a +pull request that touches only the `Governance/` folder. + +## Related Documentation + +- [Right-to-Erasure Policy](DATA_DELETION.md): deletion on request and its interaction + with a hold +- [Consent Management Policy](CONSENT_MANAGEMENT.md): retaining consent as evidence +- [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md): what is + processed, on what basis, and for how long +- [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md) and + [DPA Template](../compliance/DPA_TEMPLATE.md): retention on processors +- [Privacy Manifest Policy](../domains/PRIVACY_MANIFEST.md) and + [Mobile Telemetry Governance](../domains/MOBILE_TELEMETRY.md) +- [Children's Data Policy](../compliance/CHILDRENS_DATA.md): minimisation for data + about children +- [Incident Log](../registers/INCIDENT_LOG.md) and + [Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) +- [Security Officer role](../roles/SECURITY_OFFICER.md) diff --git a/Governance/policies/VENDOR_RISK.md b/Governance/policies/VENDOR_RISK.md new file mode 100644 index 0000000..69e83a7 --- /dev/null +++ b/Governance/policies/VENDOR_RISK.md @@ -0,0 +1,183 @@ +# Vendor Risk Management Policy + +## Purpose + +This policy defines how a third-party service or dependency is assessed before the +project relies on it, how its risk is tiered, and how that risk is reviewed over time. +Most of the software TeachLink Mobile runs is written by someone else, so the project's +security posture is largely the aggregate of its vendors' postures. + +## Scope + +This policy covers every third party whose failure or compromise would affect +TeachLink Mobile: + +- services the app calls at runtime, including the API host, authentication, push + notifications, analytics, crash reporting, and AI services; +- build and distribution services, including Expo Application Services, GitHub Actions, + and the CI providers in `.github/workflows/`; +- app stores and payment providers; +- libraries and packages, which are additionally covered by the + [Dependency Register](../registers/DEPENDENCY_REGISTER.md); and +- infrastructure and hosting, including anything that stores data. + +Processors that handle personal data are additionally governed by the +[DPA Template](../compliance/DPA_TEMPLATE.md) and recorded in the +[Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md). This policy decides +whether a vendor is acceptable and how that acceptance is kept current. + +## Vetting Criteria + +A vendor is assessed against these criteria before it is relied upon. The assessment is +recorded, not merely performed, so that a later reader can see why the vendor was +accepted. + +| Criterion | Question | Evidence | +| --- | --- | --- | +| Purpose and necessity | What does it do, and could the project do without it? | A stated purpose; the alternative considered | +| Data handled | What data reaches it, including metadata and content? | The categories listed in the [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md) | +| Security posture | Does it encrypt data, manage access, and disclose incidents? | Public documentation, certifications where relevant, and the answers to a security questionnaire | +| Subprocessors | Who else receives the data? | The vendor's own subprocessor list, recorded in the [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md) | +| Data location | Where is the data stored and processed? | The vendor's stated regions, per the [Data Residency Policy](DATA_RESIDENCY.md) | +| Retention and deletion | How long is data kept, and can it be deleted? | Documented retention and a deletion mechanism | +| Compliance | Does it meet the obligations the project owes users? | Terms, DPAs, and certifications as relevant | +| Licence and terms | What are the terms of use, and can the project comply? | The licence, checked against `license-allowlist.json` and `license-exceptions.json` | +| Exit | How would the project replace it, and how long would that take? | A migration estimate and the data format involved | +| Track record | Has it had an outage, breach, or controversy? | Public record, and the project's own incident history | +| Maintenance | Is it maintained, and how will it be kept current? | Release activity and the project's update path | + +Rules that apply to the assessment: + +- **Necessity is assessed first.** A vendor that cannot justify its existence is not + assessed on how safe it is, because not using it is the safest option available. +- **A missing answer is a finding.** A vendor that will not answer a security question + is treated as having failed it, not as having passed by silence. +- **Self-declared certifications are a starting point.** A certificate is dated and + scoped; the project's assessment is of the service it actually uses. +- **A new dependency is a vendor decision**, not a package-manager decision. Installing + something is subject to this policy, as the + [Bot and Automation Governance Policy](BOT_AUTOMATION.md) describes for automated + updates. +- **Assessment happens before reliance, not after an incident.** A vendor handling data + before its assessment is complete is a finding with a deadline, not a fait accompli. + +## Risk Tiers + +Vendors are tiered by the consequence of their failure or compromise, and the tier sets +what the project owes each one. + +| Tier | Applies to | Requirements | +| --- | --- | --- | +| **Tier 1 — Critical** | Vendors handling authentication, personal data including children's data, payment, release signing, or the build chain | Security questionnaire answered, DPA in place, incident notification terms, encryption verified, annual reassessment, named owner, and a tested exit path | +| **Tier 2 — Standard** | Vendors handling limited or pseudonymised data, or providing non-security-critical runtime functions | DPA or terms reviewed, privacy and retention position documented, subprocessor list recorded, semiannual reassessment, named owner | +| **Tier 3 — Low** | Build-time and developer-experience tools that never see production user data | Licence and terms reviewed, recorded in the [Dependency Register](../registers/DEPENDENCY_REGISTER.md), annual reassessment on use rather than on schedule | +| **Tier 4 — Rejected** | Vendors that fail a Tier 1 or 2 criterion and will not remediate | Not used. The dependency is removed, or the function is rebuilt, or the feature is withdrawn | + +Rules that apply across tiers: + +- **The tier is set by consequence, not by how much the project likes the vendor.** A + widely used vendor handling children's data is Tier 1. +- **A tier can move up.** A vendor is promoted immediately when it starts handling data + it did not handle before, or when it is acquired by a party with a different risk + profile. +- **A Tier 4 vendor is not a vendor the project keeps and dislikes.** It is either + removed or accepted through an exception with an expiry. +- **A vendor used only in CI that receives a repository token** is Tier 1, because that + token can write to the default branch. Build-time access to source is not a low risk. + +## Review Cadence + +| Vendor tier | Review cadence | Reviewer | Output | +| --- | --- | --- | --- | +| Tier 1 | **Every 12 months**, and on any material change | [Security Officer](../roles/SECURITY_OFFICER.md) | Re-approved, escalated with a remediation plan, or replaced | +| Tier 2 | **Every 12 months** | Maintainer owning the integration | Confirmed current, or re-tiered | +| Tier 3 | Every 12 months, or on use | Maintainer owning the integration | Licence and terms reconfirmed | +| Tier 4 | On rejection | [Security Officer](../roles/SECURITY_OFFICER.md) | Decision recorded, removal tracked | + +Reviews are also triggered, regardless of the calendar: + +- a vendor announces a breach, an outage, or a change in ownership; +- a vendor changes its subprocessors, regions, or retention period, which follows the + notice process in the + [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md#change-notification-process); +- an advisory affects a vendor's product, handled under the + [Vulnerability Remediation SLA Policy](VULN_SLA.md); +- a vendor is acquired, changes its terms materially, or discontinues a product the + project depends on; or +- the project changes what it sends a vendor. + +A review that finds drift updates the [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md) +and the [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md) in the same change, +so that an assessment never disagrees with the registers. + +## Ongoing Monitoring + +Between reviews, the project watches for signals rather than waiting: + +- **Dependency advisories**, from `audit.yml` on push and on the weekly schedule, routed + through the [Vulnerability Remediation SLA Policy](VULN_SLA.md). +- **Licence changes** in a new version, which can move a dependency between categories + without any code change; checked by `license-audit.js` and the + [Dependency Register](../registers/DEPENDENCY_REGISTER.md). +- **Vendor status and incident pages**, checked at Tier 1 review rather than + continuously, since no automated monitor is available for every vendor. +- **New subprocessor announcements**, which are a contractual notification rather than + something to discover. + +## Exit Planning + +Every Tier 1 vendor has a written exit position, so that a vendor failure is a managed +event rather than an outage: + +- **What would be replaced**, and with what alternative identified during vetting. +- **How long a migration would take**, stated as a rough range so it can be judged + against the vendor's notification period. +- **Where the data lives and in what format**, so it can be exported before switching. +- **What happens to the data on exit**, including deletion by the vendor, confirmed + under the [Right-to-Erasure Policy](DATA_DELETION.md) and the + [DPA Template](../compliance/DPA_TEMPLATE.md). + +A Tier 1 vendor with no identified alternative is a finding at review, not an accepted +state. + +## Enforcement Status + +- Automated signals exist and are real: `audit.yml` fails on high and critical + dependency advisories on push and weekly, and `license-audit.js` checks licences + against the allowlist. +- Vetting, tiering, and the review cadence are human activities. No system tracks a + vendor's assessment date or prompts when one lapses, so the calendar is the control. +- The registers are the evidence base; their value depends on being updated when a + vendor changes. + +## Exceptions + +A vendor used without a completed assessment, or above its tier, is recorded in the +[Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md) with the reason, the +compensating control, an approver holding the authority to grant it, and an expiry no +more than 12 months ahead. A vendor processing children's data without the +[Children's Data Policy](../compliance/CHILDRENS_DATA.md) conditions met cannot be +excepted under this policy. + +## Ownership and Review + +The [Security Officer](../roles/SECURITY_OFFICER.md) owns this policy. It is reviewed +when a new vendor category appears, when the tiering criteria change, and at least once +every 12 months. Changes are proposed in a pull request that touches only the +`Governance/` folder. + +## Related Documentation + +- [Subprocessor Register](../registers/SUBPROCESSOR_REGISTER.md) and + [DPA Template](../compliance/DPA_TEMPLATE.md) +- [Data Processing Register](../registers/DATA_PROCESSING_REGISTER.md) +- [Dependency Register](../registers/DEPENDENCY_REGISTER.md) and + [Risk Register](../registers/RISK_REGISTER.md) +- [Data Residency Policy](DATA_RESIDENCY.md) and + [Record Retention and Legal Hold Policy](RECORD_RETENTION.md) +- [Vulnerability Remediation SLA Policy](VULN_SLA.md) and + [Secret Rotation Policy](SECRET_ROTATION.md) +- [Children's Data Policy](../compliance/CHILDRENS_DATA.md) +- [Security Policy](../SECURITY_POLICY.md) and + [Security Officer role](../roles/SECURITY_OFFICER.md) +- [Exception and Waiver Register](../registers/EXCEPTION_REGISTER.md)