Intelligence

Artifacts

Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only.

Repository
README.md
CONSTITUTION_COMPLIANCE_AUDIT_V1.mdREADME.md
repositories/aaf-holdings/hq01/lib/uploads/config.ts
3.1 KB
import path from "node:path";

/**
 * Configuration for the HQ01 Artifact Upload flow.
 *
 * The destination categories below are the *entire* security boundary for
 * writes: the browser only ever sends a category **key**, never a path. The
 * server maps that key to a fixed absolute directory. There is no way for a
 * caller to write outside this allowlist, which is what keeps HQ01 from
 * exposing arbitrary filesystem writes.
 */

/**
 * Base of the upload tree. Defaults to the AAF workspace root (which is also the
 * Artifacts explorer root, so uploaded files appear there immediately).
 * Overridable for tests via HQ01_UPLOAD_ROOT.
 */
export const UPLOAD_ROOT =
  process.env.HQ01_UPLOAD_ROOT?.trim() || "/srv/aaf";

/** Maximum accepted upload size: 25 MB. */
export const MAX_UPLOAD_BYTES = 25 * 1024 * 1024;

/** The only file extensions HQ01 will accept. */
export const ALLOWED_EXTENSIONS = new Set([
  ".pdf",
  ".md",
  ".txt",
  ".yaml",
  ".yml",
  ".json",
]);

export interface UploadCategory {
  /** Stable key sent by the client. */
  key: string;
  /** Human label shown in the UI. */
  label: string;
  /** One-line description of what belongs here. */
  blurb: string;
  /** Absolute destination directory (created on demand). */
  dir: string;
}

/**
 * The fixed destination allowlist. `dir` is always derived from UPLOAD_ROOT, so
 * every target is contained within the workspace and nothing else is writable.
 */
export const UPLOAD_CATEGORIES: UploadCategory[] = [
  {
    key: "pdf",
    label: "PDF Artifact",
    blurb: "Reference PDFs and scanned documents.",
    dir: path.join(UPLOAD_ROOT, "artifacts", "pdf"),
  },
  {
    key: "canonical",
    label: "Canonical Document",
    blurb: "Parent doctrine — the highest-level governing documents (CANONICAL_*).",
    dir: path.join(UPLOAD_ROOT, "canonical"),
  },
  {
    key: "exec-constitution",
    label: "Executive Constitution",
    blurb: "Standing authority and rules for an executive.",
    dir: path.join(UPLOAD_ROOT, "constitutions", "executives"),
  },
  {
    key: "dept-constitution",
    label: "Department Constitution",
    blurb: "Standing authority for a department.",
    dir: path.join(UPLOAD_ROOT, "constitutions", "departments"),
  },
  {
    key: "roadmap",
    label: "Roadmap",
    blurb: "Department and product roadmaps.",
    dir: path.join(UPLOAD_ROOT, "roadmaps"),
  },
  {
    key: "doctrine",
    label: "Doctrine",
    blurb: "Promoted, ratified doctrine and lessons.",
    dir: path.join(UPLOAD_ROOT, "doctrine"),
  },
  {
    key: "template",
    label: "Template",
    blurb: "Reusable work-order and document templates.",
    dir: path.join(UPLOAD_ROOT, "templates"),
  },
  {
    key: "inbox",
    label: "Uploads Inbox",
    blurb: "Default drop zone for unsorted uploads.",
    dir: path.join(UPLOAD_ROOT, "uploads"),
  },
];

export function getCategory(key: string): UploadCategory | undefined {
  return UPLOAD_CATEGORIES.find((c) => c.key === key);
}

/** A presentable, comma-free list of accepted extensions for the UI. */
export const ALLOWED_EXTENSIONS_LABEL = [...ALLOWED_EXTENSIONS].join(" ");

root · /srv/aaf