Skip to content

Development Guide

Elman Mohammadi edited this page Oct 6, 2026 · 1 revision

Development Guide

This guide describes how to work on Secure Package without weakening its security boundaries.

Repository structure

app/
  Api/
  Archive/
  Client/
  Crypto/
  Project/
  Security/
  Storage/

bin/
config/
docs/
public/
tests/
archive/

Code organization

The project uses PSR-4 autoloading:

SecurePackage\\ -> app/

A class such as:

SecurePackage\\Project\\V14PackageReader

maps to:

app/Project/V14PackageReader.php

Core engineering rule

Do not mix security responsibilities without a reason.

For example:

  • cryptographic primitives belong in app/Crypto;
  • package format validation belongs in app/Project;
  • HTTP/session policy belongs in app/Security and app/Api;
  • ZIP safety belongs in app/Archive and PackageArchive;
  • runtime persistence belongs in app/Storage.

This makes security review easier because each boundary has a narrow purpose.

Fail-closed development

When adding a parser or verifier, prefer:

unknown field -> reject
invalid type -> reject
invalid encoding -> reject
missing required data -> reject
ambiguous path -> reject
unexpected extra data -> reject

Avoid permissive fallbacks that silently reinterpret security-sensitive data.

Adding a new package field

A new V14 header or manifest field should trigger a deliberate schema decision.

Ask:

  1. Is it authenticated?
  2. Is it included in the header binding if it affects cryptographic meaning?
  3. Does the parser enforce its type and range?
  4. Does it create a new downgrade or substitution possibility?
  5. Does the test suite cover both valid and malicious forms?

Adding a new cryptographic use

Do not reuse an existing key merely because it is convenient.

Prefer a new explicit HKDF purpose/context when a distinct security purpose exists.

For example:

purpose = "manifest"
purpose = "filename"
purpose = "files"
purpose = "file"

The purpose string is part of the domain separation.

New authenticated data

Associated data should bind the operation to the correct package context whenever practical.

Examples already used by V14 include package ID, header binding, node ID, file ID, chunk index, and expected plaintext size.

Restore changes require adversarial tests

Any change to:

  • filename parsing
  • path normalization
  • archive extraction
  • package inventory
  • blob verification
  • manifest validation
  • restore ordering
  • temporary file handling

should add or update negative tests.

Do not rely only on a successful round-trip.

Security-sensitive output

Do not add passwords, patterns, recovery keys, CSRF tokens, session cookies, or authorization data to logs.

Audit events should remain useful without becoming a secret storage channel.

Running the checks

php bin/self-check.php
php bin/source-audit.php
php bin/security-test.php --full
find public/client -type f -name '*.js' -print0 | xargs -0 -n1 node --check
composer validate --strict --no-check-publish
composer audit --no-interaction

Release discipline

Before publishing a release:

  1. update VERSION deliberately;
  2. update CHANGELOG.md with user-visible changes;
  3. verify tests;
  4. generate a real composer.lock when dependencies are involved;
  5. sign the active source tree;
  6. verify the signature through an external trust root;
  7. package and checksum the release;
  8. verify after deployment.

Versioning

Version numbers describe releases; commit messages describe changes.

Prefer:

feat(crypto): ...
fix(storage): ...
fix(security): ...
refactor(api): ...
chore(ci): ...

Use release tags such as:

v14.1.0
v14.1.1
v14.2.0

Do not use a version number as the name of every commit.

Pull requests

Security-sensitive changes should explain:

  • the threat or bug;
  • the exact boundary changed;
  • the new invariant;
  • the tests added;
  • any deployment impact;
  • any format compatibility impact.

Independent review

For cryptographic or parser changes, independent review should be treated as a target requirement rather than assumed from automated tests.

Clone this wiki locally