From e8a28a603415d9d2b3054c021b95291aa7cf9ef0 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 22:01:06 -0500
Subject: [PATCH 01/20] Add new marketing homepage
Updates the homepage with new marketing content and styling.
Co-Authored-By: Claude Sonnet 4.5
---
src/css/marketing.css | 228 +++++++++++++++++++++++++++
src/pages/index.module.css | 271 ++++++++++++++++++++++++++++++++
src/pages/index.tsx | 306 ++++++++++++++++++++++++++-----------
3 files changed, 715 insertions(+), 90 deletions(-)
create mode 100644 src/css/marketing.css
diff --git a/src/css/marketing.css b/src/css/marketing.css
new file mode 100644
index 00000000..ad90eb17
--- /dev/null
+++ b/src/css/marketing.css
@@ -0,0 +1,228 @@
+/* Marketing Homepage Styles */
+
+.marketing-hero {
+ padding: 4rem 0;
+ position: relative;
+ overflow: hidden;
+}
+
+.marketing-hero--primary {
+ background: linear-gradient(135deg, var(--ifm-color-primary) 0%, var(--ifm-color-primary-dark) 100%);
+ color: white;
+}
+
+.marketing-hero--secondary {
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+ color: var(--ifm-color-gray-900);
+}
+
+.marketing-hero--dark {
+ background: linear-gradient(135deg, var(--ifm-color-gray-900) 0%, var(--ifm-color-gray-800) 100%);
+ color: white;
+}
+
+.marketing-hero--accent {
+ background: linear-gradient(135deg, var(--ifm-color-success) 0%, var(--ifm-color-success-dark) 100%);
+ color: white;
+}
+
+.hero-content {
+ display: flex;
+ align-items: center;
+ gap: 3rem;
+ min-height: 400px;
+}
+
+.hero-content--reverse {
+ flex-direction: row-reverse;
+}
+
+.hero-text {
+ flex: 1;
+}
+
+.hero-visual {
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.hero-icon {
+ font-size: 8rem;
+ opacity: 0.9;
+ filter: drop-shadow(0 4px 8px rgba(0,0,0,0.1));
+}
+
+.hero-title {
+ font-size: 3.5rem;
+ font-weight: 800;
+ margin-bottom: 1.5rem;
+ line-height: 1.2;
+}
+
+.hero-subtitle {
+ font-size: 1.3rem;
+ margin-bottom: 2rem;
+ opacity: 0.9;
+ line-height: 1.6;
+}
+
+.hero-actions {
+ display: flex;
+ gap: 1rem;
+ flex-wrap: wrap;
+}
+
+.hero-button {
+ padding: 0.75rem 2rem;
+ font-size: 1.1rem;
+ font-weight: 600;
+ border-radius: 8px;
+ text-decoration: none;
+ transition: all 0.2s ease;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.hero-button--primary {
+ background: rgba(255,255,255,0.2);
+ color: white;
+ border: 2px solid rgba(255,255,255,0.3);
+}
+
+.hero-button--primary:hover {
+ background: rgba(255,255,255,0.3);
+ color: white;
+ text-decoration: none;
+ transform: translateY(-2px);
+}
+
+.hero-button--secondary {
+ background: transparent;
+ color: inherit;
+ border: 2px solid currentColor;
+}
+
+.hero-button--secondary:hover {
+ background: rgba(255,255,255,0.6);
+ color: gray;
+ text-decoration: none;
+ transform: translateY(-2px);
+}
+
+.hero-button--solid {
+ background: var(--ifm-color-primary);
+ color: white;
+ border: 2px solid var(--ifm-color-primary);
+}
+
+.hero-button--solid:hover {
+ background: var(--ifm-color-primary-dark);
+ border-color: var(--ifm-color-primary-dark);
+ color: white;
+ text-decoration: none;
+ transform: translateY(-2px);
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .hero-content {
+ flex-direction: column !important;
+ text-align: center;
+ gap: 2rem;
+ min-height: 300px;
+ }
+
+ .hero-content--reverse {
+ flex-direction: column !important;
+ }
+
+ .hero-title {
+ font-size: 2.5rem;
+ }
+
+ .hero-subtitle {
+ font-size: 1.1rem;
+ }
+
+ .hero-icon {
+ font-size: 5rem;
+ }
+
+ .hero-actions {
+ justify-content: center;
+ }
+}
+
+/* Navigation Enhancement */
+.navbar {
+ backdrop-filter: blur(10px);
+ background: rgba(255, 255, 255, 0.95);
+ border-bottom: 1px solid rgba(0,0,0,0.1);
+}
+
+/* Animation Classes */
+.fade-in {
+ animation: fadeIn 0.8s ease-out;
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.slide-in-right {
+ animation: slideInRight 1s ease-out;
+}
+
+@keyframes slideInRight {
+ from {
+ opacity: 0;
+ transform: translateX(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+.slide-in-left {
+ animation: slideInLeft 1s ease-out;
+}
+
+@keyframes slideInLeft {
+ from {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+/* Visual enhancements */
+.hero-icon-container {
+ position: relative;
+}
+
+.hero-icon-container::before {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 120%;
+ height: 120%;
+ background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
+ border-radius: 50%;
+ z-index: -1;
+}
\ No newline at end of file
diff --git a/src/pages/index.module.css b/src/pages/index.module.css
index d1a89ba6..41ed7ea5 100644
--- a/src/pages/index.module.css
+++ b/src/pages/index.module.css
@@ -3,3 +3,274 @@
* and scoped locally.
*/
+/* Marketing Homepage Styles */
+
+/* Hero Sections */
+.marketing-hero {
+ padding: 6rem 0;
+ position: relative;
+ overflow: hidden;
+}
+
+.marketing-hero--primary {
+ background: linear-gradient(135deg, var(--ifm-color-primary) 0%, var(--ifm-color-primary-darker) 100%);
+ color: white;
+}
+
+.marketing-hero--secondary {
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+ color: var(--ifm-color-emphasis-800);
+}
+
+.marketing-hero--dark {
+ background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
+ color: white;
+}
+
+.marketing-hero--accent {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+}
+
+/* Hero Content Layout */
+.hero-content {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 4rem;
+ align-items: center;
+ min-height: 400px;
+}
+
+.hero-content--reverse {
+ grid-template-areas: "visual text";
+}
+
+.hero-content--reverse .hero-text {
+ grid-area: text;
+}
+
+.hero-content--reverse .hero-visual {
+ grid-area: visual;
+}
+
+.hero-text {
+ z-index: 2;
+}
+
+.hero-title {
+ font-size: 3rem;
+ font-weight: 800;
+ line-height: 1.2;
+ margin-bottom: 1.5rem;
+ background: linear-gradient(135deg, currentColor 0%, rgba(255,255,255,0.8) 100%);
+ background-clip: text;
+ -webkit-background-clip: text;
+}
+
+.hero-subtitle {
+ font-size: 1.25rem;
+ line-height: 1.6;
+ margin-bottom: 2rem;
+ opacity: 0.9;
+}
+
+/* Hero Actions */
+.hero-actions {
+ display: flex;
+ gap: 1rem;
+ flex-wrap: wrap;
+}
+
+.hero-button {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 1rem 2rem;
+ border-radius: 0.5rem;
+ font-weight: 600;
+ text-decoration: none;
+ transition: all 0.3s ease;
+ border: 2px solid;
+ font-size: 1rem;
+}
+
+.hero-button--primary {
+ background: rgba(255, 255, 255, 0.1);
+ border-color: rgba(255, 255, 255, 0.3);
+ color: white;
+ backdrop-filter: blur(10px);
+}
+
+.hero-button--primary:hover {
+ background: rgba(255, 255, 255, 0.2);
+ color: white;
+ text-decoration: none;
+ transform: translateY(-2px);
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
+}
+
+.hero-button--secondary {
+ background: transparent;
+ border-color: currentColor;
+ color: inherit;
+}
+
+.hero-button--secondary:hover {
+ background: currentColor;
+ color: white;
+ text-decoration: none;
+ transform: translateY(-2px);
+}
+
+.hero-button--solid {
+ background: var(--ifm-color-primary);
+ border-color: var(--ifm-color-primary);
+ color: white;
+}
+
+.hero-button--solid:hover {
+ background: var(--ifm-color-primary-dark);
+ border-color: var(--ifm-color-primary-dark);
+ color: white;
+ text-decoration: none;
+ transform: translateY(-2px);
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
+}
+
+/* Hero Visual */
+.hero-visual {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+}
+
+.hero-icon-container {
+ width: 200px;
+ height: 200px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(255, 255, 255, 0.1);
+ border-radius: 50%;
+ backdrop-filter: blur(10px);
+ border: 2px solid rgba(255, 255, 255, 0.2);
+}
+
+.hero-icon {
+ font-size: 4rem;
+ color: currentColor;
+}
+
+/* Animations */
+.fade-in {
+ animation: fadeIn 1s ease-out;
+}
+
+.slide-in-right {
+ animation: slideInRight 1s ease-out;
+}
+
+.slide-in-left {
+ animation: slideInLeft 1s ease-out;
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes slideInRight {
+ from {
+ opacity: 0;
+ transform: translateX(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes slideInLeft {
+ from {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .hero-content {
+ grid-template-columns: 1fr;
+ gap: 2rem;
+ text-align: center;
+ }
+
+ .hero-content--reverse {
+ grid-template-areas:
+ "text"
+ "visual";
+ }
+
+ .hero-title {
+ font-size: 2.5rem;
+ }
+
+ .hero-subtitle {
+ font-size: 1.1rem;
+ }
+
+ .hero-actions {
+ justify-content: center;
+ }
+
+ .hero-button {
+ padding: 0.875rem 1.5rem;
+ font-size: 0.9rem;
+ }
+
+ .marketing-hero {
+ padding: 4rem 0;
+ }
+
+ .hero-icon-container {
+ width: 150px;
+ height: 150px;
+ }
+
+ .hero-icon {
+ font-size: 3rem;
+ }
+}
+
+@media (max-width: 480px) {
+ .hero-title {
+ font-size: 2rem;
+ }
+
+ .hero-subtitle {
+ font-size: 1rem;
+ }
+
+ .hero-actions {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .hero-button {
+ width: 100%;
+ max-width: 280px;
+ justify-content: center;
+ }
+}
+
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 5304464d..7231221d 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,103 +1,229 @@
import React from "react";
import Layout from "@theme/Layout";
import Head from "@docusaurus/Head";
-import { Columns, Hero, Features, Feedback } from "../components/Homepage";
+import styles from "./index.module.css";
export default function Home() {
return (
-
+
-
+
-
-
-
- OpenTDF is an open source system for implementing data centric security.
- It provides the basic services required to enable the definition, application,
- and enforcement of attribute based policies using the Trust Data Format (TDF).
- TDF is an open standard that enables you to cryptographically bind
- attribute based access control (ABAC) policy to a data object so that
- the policy travels with the data wherever it goes.
-
-
- OpenTDF builds upon a decade of experience at Virtru
- protecting data objects at scale using the Trusted Data Format
- for organizations of all sizes and across all industries.
-
-
-
-
-
- Today's cybersecurity landscape is increasingly adopting and requiring Zero Trust models and frameworks.
- Zero Trust operates on the principle of "never trust, always verify,"
- ensuring that every access request is authenticated, authorized, and encrypted,
- regardless of its origin. OpenTDF implements this model by providing an open-source framework, specification, and set of services
- that prioritizes the protection and integrity of data at every stage.
-
-
- By integrating OpenTDFβs data security features with a Zero Trust architecture,
- organizations can enforce strict access controls, ensure data is continuously monitored,
- and maintain comprehensive visibility into data interactions. This synergy not only
- minimizes the risk of data breaches but also fosters a secure environment where data
- can be shared and utilized with confidence. Together, Zero Trust and OpenTDF empower businesses
- to uphold the highest standards of data security in an interconnected world.
-
-
-
-
- In 2023, the OpenTDF team undertook a significant re-architecture
- of the OpenTDF platform to enhance its extensibility and interoperability,
- responding to the evolving needs of our diverse user base and the dynamic cybersecurity landscape.
- See our {" "}Github Organization Page to navigate the new repositories.
-
-
- This comprehensive overhaul involved simplifying core service components,
- adopting standardized policy schemas, and improving platform APIs and SDKs both in
- developer experience and in capability. By focusing on extensibility, we have enabled
- developers to customize and extend OpenTDFβs functionalities to suit specific use cases,
- fostering innovation and adaptability. As we continue to advance, our focus remains on empowering the community with a secure, adaptable,
- and interoperable platform that meets the highest standards of data protection and fosters collaborative innovation.
-
-
- Through the sponsorship of Virtru and its partners, the OpenTDF project has been
- meeting the needs of customers across industries and use cases. Check out{" "}
-
- Virtru Data Security Platform
- {" "}
- for more.
+
+
+ {/* Hero 1: Main Value Proposition */}
+
+
+
+
+
Protect the Data, Build the Future
+
+ Zero-trust data protection that travels with your data wherever it goes.
+ OpenTDF cryptographically binds access control policies directly to data objects,
+ ensuring your data remains secure regardless of network boundaries or storage location.
+
+
+
+
+
+
+
+
+ {/* Hero 2: Problem/Solution */}
+
+
+
+
+
Traditional Security Fails When Data Leaves the Perimeter
+
+ Once data crosses network boundaries, traditional security models lose control.
+ OpenTDF solves this by cryptographically binding policies to data objects themselves,
+ creating self-protecting data that enforces access controls anywhere it travels.
+
+
+
+
+
+
+
+
+ {/* Hero 3: Developer-First */}
+
+
+
+
+
Built for Developers
+
+ Native SDKs for Go, Java, and JavaScript. RESTful APIs. Comprehensive documentation.
+ Get started in minutes, not months. OpenTDF provides the tools developers need to build
+ secure applications without sacrificing speed or simplicity.
+
+
+
+
+
+
+
+
+ {/* Hero 4: Enterprise Trust */}
+
+
+
+
+
Trusted by Organizations Worldwide
+
+ Built on a decade of Virtru's experience protecting data at scale. OpenTDF powers
+ secure data sharing for organizations across industriesβfrom healthcare and finance
+ to government and defense. Battle-tested, enterprise-ready, open source.
+
+
+
+
+
+
+
+
+ {/* Hero 5: Standards & Compliance */}
+
+
+
+
+
Standards-Based Security
+
+ Built on the proven NIST ABAC model for interoperability and compliance.
+ OpenTDF follows established standards for attribute-based access control,
+ ensuring your data protection strategy is future-proof and audit-ready.
+
+
+
+
+
+
+
+
+ {/* Hero 6: Community */}
+
+
+
+
+
Join the Movement
+
+ Open source, open community. Shape the future of data-centric security with developers,
+ security professionals, and organizations from around the world. Contribute code,
+ share ideas, and help build the next generation of data protection.
+
+
+
+
+
+
+
+
+ {/* Final CTA Section */}
+
+
+
+ Ready to Protect Your Data?
+
+
+ Choose your path and start building with OpenTDF today.
-
-
-
- {/* */}
-
-
-
-
-
- Virtru, the sponsor of the OpenTDF developer community, would love to hear from you!
-
-
- We're developers, too, and as we mature the project, we're curious what you're building, and what kind of problems you may be encountering or are trying to solve.
-
-
- You can provide anonymous feedback (name, email, and company are not required fields on this form), or share your contact information for access to curated resources, updates, and if you request a response.
-
-
+
+
+
+
);
From 032e63b2489a5e31710195e4b9b53c9cfb17518b Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 22:33:29 -0500
Subject: [PATCH 02/20] Add CC BY 4.0 license and update README
Co-Authored-By: Claude Sonnet 4.5
---
LICENSE | 89 +++++++++-----------------
README.md | 187 ++++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 189 insertions(+), 87 deletions(-)
diff --git a/LICENSE b/LICENSE
index c9cd9ecc..26b9f75c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,7 @@
-Copyright 2025 Virtru Corporation
-This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
+Copyright 2026 Virtru Corporation
+This work is licensed under the Creative Commons Attribution 4.0 International License.
-Attribution-ShareAlike 4.0 International
+Attribution 4.0 International
=======================================================================
@@ -36,7 +36,7 @@ exhaustive, and do not form part of our licenses.
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
- wiki.creativecommons.org/Considerations_for_licensors
+ wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
@@ -51,24 +51,22 @@ exhaustive, and do not form part of our licenses.
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
- respect those requests where reasonable. More_considerations
- for the public:
- wiki.creativecommons.org/Considerations_for_licensees
+ respect those requests where reasonable. More considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
-Creative Commons Attribution-ShareAlike 4.0 International Public
-License
+Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
-Attribution-ShareAlike 4.0 International Public License ("Public
-License"). To the extent this Public License may be interpreted as a
-contract, You are granted the Licensed Rights in consideration of Your
-acceptance of these terms and conditions, and the Licensor grants You
-such rights in consideration of benefits the Licensor receives from
-making the Licensed Material available under these terms and
-conditions.
+Attribution 4.0 International Public License ("Public License"). To the
+extent this Public License may be interpreted as a contract, You are
+granted the Licensed Rights in consideration of Your acceptance of
+these terms and conditions, and the Licensor grants You such rights in
+consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
Section 1 -- Definitions.
@@ -87,11 +85,7 @@ Section 1 -- Definitions.
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
- c. BY-SA Compatible License means a license listed at
- creativecommons.org/compatiblelicenses, approved by Creative
- Commons as essentially the equivalent of this Public License.
-
- d. Copyright and Similar Rights means copyright and/or similar rights
+ c. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
@@ -99,33 +93,29 @@ Section 1 -- Definitions.
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
- e. Effective Technological Measures means those measures that, in the
+ d. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
- f. Exceptions and Limitations means fair use, fair dealing, and/or
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
- g. License Elements means the license attributes listed in the name
- of a Creative Commons Public License. The License Elements of this
- Public License are Attribution and ShareAlike.
-
- h. Licensed Material means the artistic or literary work, database,
+ f. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
- i. Licensed Rights means the rights granted to You subject to the
+ g. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
- j. Licensor means the individual(s) or entity(ies) granting rights
+ h. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
- k. Share means to provide material to the public by any means or
+ i. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
@@ -133,13 +123,13 @@ Section 1 -- Definitions.
public may access the material from a place and at a time
individually chosen by them.
- l. Sui Generis Database Rights means rights other than copyright
+ j. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
- m. You means the individual or entity exercising the Licensed Rights
+ k. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
@@ -185,13 +175,7 @@ Section 2 -- Scope.
Licensed Rights under the terms and conditions of this
Public License.
- b. Additional offer from the Licensor -- Adapted Material.
- Every recipient of Adapted Material from You
- automatically receives an offer from the Licensor to
- exercise the Licensed Rights in the Adapted Material
- under the conditions of the Adapter's License You apply.
-
- c. No downstream restrictions. You may not offer or impose
+ b. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
@@ -273,24 +257,9 @@ following conditions.
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
- b. ShareAlike.
-
- In addition to the conditions in Section 3(a), if You Share
- Adapted Material You produce, the following conditions also apply.
-
- 1. The Adapter's License You apply must be a Creative Commons
- license with the same License Elements, this version or
- later, or a BY-SA Compatible License.
-
- 2. You must include the text of, or the URI or hyperlink to, the
- Adapter's License You apply. You may satisfy this condition
- in any reasonable manner based on the medium, means, and
- context in which You Share Adapted Material.
-
- 3. You may not offer or impose any additional or different terms
- or conditions on, or apply any Effective Technological
- Measures to, Adapted Material that restrict exercise of the
- rights granted under the Adapter's License You apply.
+ 4. If You Share Adapted Material You produce, the Adapter's
+ License You apply must not prevent recipients of the Adapted
+ Material from complying with this Public License.
Section 4 -- Sui Generis Database Rights.
@@ -305,9 +274,8 @@ apply to Your use of the Licensed Material:
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
- Rights (but not its individual contents) is Adapted Material,
+ Rights (but not its individual contents) is Adapted Material; and
- including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
@@ -428,3 +396,4 @@ the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.
+
diff --git a/README.md b/README.md
index a3f04374..dab22880 100644
--- a/README.md
+++ b/README.md
@@ -1,54 +1,187 @@
-# Website
+# OpenTDF Documentation
+
+> The official documentation website for OpenTDF - an open source toolkit for zero trust, data-centric security.
+
+## About This Repository
+
+This repository contains the source code for the [OpenTDF documentation website](https://docs.opentdf.io), built using [Docusaurus](https://docusaurus.io/). The documentation provides comprehensive guides, tutorials, and reference materials for developers and organizations implementing data-centric security with OpenTDF.
+
+## What is OpenTDF?
+
+OpenTDF is an open source system for implementing data-centric security that enables:
+
+- **Zero Trust Data Protection**: Cryptographically bind access control policies to data objects
+- **Attribute-Based Access Control (ABAC)**: Fine-grained access decisions based on attributes and context
+- **Policy Travels with Data**: Security controls remain attached wherever data goes
+- **Trust Data Format (TDF)**: Open standard for self-protecting data
+
+## Documentation Structure
+
+Our documentation follows a user-needs approach with four main categories:
+
+- **π Tutorials**: Step-by-step learning experiences for hands-on practice
+- **π How-To Guides**: Problem-solving recipes for specific tasks and integrations
+- **π‘ Explanations**: Conceptual guides covering the "why" behind OpenTDF's design
+- **π Reference**: Technical specifications, API docs, and lookup information
+
+## Contributing
+
+We welcome contributions to improve our documentation! Please see our [Contributing Guide](CONTRIBUTING.md) for guidelines on:
+
+- Writing and editing documentation
+- Style and formatting standards
+- Review and approval process
+- Technical setup for contributors
+
+For style guidelines, please refer to our [Style Guide](STYLE_GUIDE.md).
+
+## Quick Links
+
+- **Live Documentation**: [docs.opentdf.io](https://docs.opentdf.io)
+- **OpenTDF Platform**: [github.com/opentdf/platform](https://github.com/opentdf/platform)
+- **TDF Format Spec**: [github.com/opentdf/spec](https://github.com/opentdf/spec)
+- **OpenTDF Organization**: [github.com/opentdf](https://github.com/opentdf)
+- **Community Discussions**: [GitHub Discussions](https://github.com/opentdf/platform/discussions)
+
+---
+
+## Local Development
This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
-### Installation
+### Prerequisites
+Before you can run the documentation locally, you'll need Node.js and npm. We recommend using nvm (Node Version Manager) to manage Node.js versions.
+
+#### Option 1: Using nvm (Recommended)
+
+nvm allows you to install and switch between different Node.js versions easily.
+
+**Installation:**
+
+- **macOS/Linux**: Follow the installation instructions at [nvm GitHub repository](https://github.com/nvm-sh/nvm#installation-and-update)
+- **Windows**: Install nvm-windows from [nvm-windows releases](https://github.com/coreybutler/nvm-windows#installation--upgrades)
+
+**Verify installation:**
+
+```bash
+nvm --version # macOS/Linux
+nvm version # Windows
```
-$ nvm use
-$ npm ci
-```
+
+#### Option 2: Direct Node.js Installation
+
+If you prefer not to use nvm:
+
+1. **Visit [nodejs.org](https://nodejs.org/)** and download **Node.js version 22** (the version specified in our `.nvmrc` file)
+2. **Follow the installation instructions** for your operating system
+3. **Verify installation:**
+
+ ```bash
+ node --version # Should show v22.x.x
+ npm --version # Should show npm version
+ ```
+
+### Installation
+
+1. **Clone the repository:**
+
+ ```bash
+ git clone https://github.com/opentdf/docs.git
+ cd docs
+ ```
+
+2. **Use the correct Node.js version** (if using nvm):
+
+ ```bash
+ nvm use # This reads the .nvmrc file and switches to Node.js v22
+ ```
+
+ If you don't have Node.js v22 installed via nvm:
+
+ ```bash
+ nvm install 22
+ nvm use 22
+ ```
+
+3. **Install dependencies:**
+
+ ```bash
+ npm ci # Installs exact versions from package-lock.json
+ ```
### Local Development
-```
-$ npm run start
-```
+ ```bash
+ npm run start
+ ```
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
### Build
-```
-$ npm run build
-```
+ ```bash
+ npm run build
+ ```
This command generates static content into the `build` directory and can be served using any static contents hosting service.
-### Preview Deployment
+### Testing with Feature Branches
-Deploy to a Surge preview domain for testing changes before merging to production. **A free Surge account is required** - you'll be prompted to sign up the first time you deploy.
+The documentation site pulls content from multiple upstream repositories using Docusaurus remote content plugins. By default, content is fetched from the `main` branch of each repository. You can override this behavior using environment variables to test documentation changes from feature branches before they're merged.
-**Important:** Each developer should use a unique preview domain name to avoid conflicts. Use a descriptive name based on your ticket number or feature:
+**Available Environment Variables:**
-```bash
-# Build the site
-npm run build
+- `PLATFORM_BRANCH` - Controls which branch to fetch from `opentdf/platform` (default: `main`)
+- `SPEC_BRANCH` - Controls which branch to fetch from `opentdf/spec` (default: `main`)
+- `OTDFCTL_BRANCH` - Controls which branch to fetch from `opentdf/otdfctl` (default: `main`)
+
+**Examples:**
-# Deploy to your unique preview URL
-# Replace with your ticket number or feature name
-npx surge build opentdf-docs-preview-.surge.sh
+Test with all feature branches:
+```bash
+PLATFORM_BRANCH=jps-updates SPEC_BRANCH=jps-updates OTDFCTL_BRANCH=jps-updates npm run build
```
-**Examples:**
+Test with a single feature branch:
```bash
-# Using ticket number
-npx surge build opentdf-docs-preview-dspx-2345.surge.sh
+SPEC_BRANCH=feature-branch-name npm run build
+```
-# Using feature description
-npx surge build opentdf-docs-preview-troubleshooting-updates.surge.sh
+Test in development mode with feature branches:
+```bash
+PLATFORM_BRANCH=my-feature npm run start
```
-Your preview will be available at `https://opentdf-docs-preview-.surge.sh/`
+**Use Cases:**
+
+- **Before merging PRs**: Test how documentation changes from upstream repos will look when integrated
+- **Cross-repo changes**: When making coordinated changes across multiple repositories, test the full integration locally
+- **Debugging**: Investigate issues with specific branches without affecting your local main branch
+
+**Note**: The branches must exist in the respective GitHub repositories and be accessible (public or you have access).
+
+---
+
+## License
+
+This documentation is licensed under the [Creative Commons Attribution 4.0 International License (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/).
+
+### License Change Notice
+
+**Effective Date: February 13, 2026**
+
+This project's documentation license has changed from:
+- **Previous:** Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
+- **New:** Creative Commons Attribution 4.0 International (CC BY 4.0)
+
+**What this means:**
+- β
You can use, adapt, and share this documentation under any terms
+- β
You only need to provide attribution to the original work
+- β
No longer required to share derivative works under the same license (ShareAlike requirement removed)
+
+**Rationale:** To make the documentation more accessible and easier to integrate into various projects and contexts while maintaining proper attribution.
+
+All content committed after February 13, 2026 is licensed under CC BY 4.0. Content created before this date was released under CC BY-SA 4.0.
-**Note:** The first time you deploy, Surge will prompt you to create a free account or login.
+See the [LICENSE](LICENSE) file for the full legal text.
From 6f2007178b43e9fba25b8eeec67ba3f47e672721 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 22:44:04 -0500
Subject: [PATCH 03/20] Add marketing.css import for homepage styles
Co-Authored-By: Claude Sonnet 4.5
---
src/css/custom.css | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/css/custom.css b/src/css/custom.css
index 4054e8a9..740935f3 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -4,6 +4,9 @@
* work well for content-centric websites.
*/
+/* Import marketing styles for homepage */
+@import './marketing.css';
+
/* You can override the default Infima variables here. */
/* :root {
--ifm-color-primary: #2e8555;
From 828d7553d144a08b37ddc053d654f02b7b3ee5cc Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 22:45:55 -0500
Subject: [PATCH 04/20] Update Get Started button to link to /getting-started
Co-Authored-By: Claude Sonnet 4.5
---
src/pages/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 7231221d..33c3036e 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -24,7 +24,7 @@ export default function Home() {
ensuring your data remains secure regardless of network boundaries or storage location.
-
+
Get Started
From f76e6983162b218b84a3cb63d554c0d8dd252103 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 22:47:39 -0500
Subject: [PATCH 05/20] Update View Documentation button to link to
/introduction
Co-Authored-By: Claude Sonnet 4.5
---
src/pages/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 33c3036e..584d3b1a 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -28,7 +28,7 @@ export default function Home() {
Get Started
-
+
View Documentation
From 9939da255ca5e3103c86f55ae7f6bdde47c2f47b Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 22:54:29 -0500
Subject: [PATCH 06/20] Update Learn the Concepts button to link to
/category/components-and-services
Co-Authored-By: Claude Sonnet 4.5
---
src/pages/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 584d3b1a..f9a86650 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -55,7 +55,7 @@ export default function Home() {
creating self-protecting data that enforces access controls anywhere it travels.
-
+
Learn the Concepts
From b5b23db82d6d9b7966d88297f93b8cbd3d7bdab9 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 22:57:48 -0500
Subject: [PATCH 07/20] Update Learn the Concepts button to link to
/category/concepts
Co-Authored-By: Claude Sonnet 4.5
---
src/pages/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index f9a86650..db1d0c42 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -55,7 +55,7 @@ export default function Home() {
creating self-protecting data that enforces access controls anywhere it travels.
-
+
Learn the Concepts
From e5ab7b0b4deda2a0fba80cfe756d4228d6cf0876 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 22:59:43 -0500
Subject: [PATCH 08/20] Update Quick Start button to link to /quickstart
Co-Authored-By: Claude Sonnet 4.5
---
src/pages/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index db1d0c42..1d3a05c8 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -86,7 +86,7 @@ export default function Home() {
secure applications without sacrificing speed or simplicity.
-
+
Quick Start
From 0733d6ed27bb2c0c366ea291b7157a51465070b9 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 23:01:37 -0500
Subject: [PATCH 09/20] Update API Reference button to link to /OpenAPI-clients
Co-Authored-By: Claude Sonnet 4.5
---
src/pages/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 1d3a05c8..e4f00d40 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -90,7 +90,7 @@ export default function Home() {
Quick Start
-
+
API Reference
From 50f653f0ed9e24fa00045ea938923d20333cf020 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Fri, 13 Feb 2026 23:06:58 -0500
Subject: [PATCH 10/20] Add new Java SDK collection examples
Add decrypt and encrypt collection example code samples.
Co-Authored-By: Claude Sonnet 4.5
---
.../java/decrypt-collection-example.mdx | 37 ++++++++++++++++
.../java/encrypt-collection-example.mdx | 42 +++++++++++++++++++
2 files changed, 79 insertions(+)
create mode 100644 code_samples/java/decrypt-collection-example.mdx
create mode 100644 code_samples/java/encrypt-collection-example.mdx
diff --git a/code_samples/java/decrypt-collection-example.mdx b/code_samples/java/decrypt-collection-example.mdx
new file mode 100644
index 00000000..05731c6f
--- /dev/null
+++ b/code_samples/java/decrypt-collection-example.mdx
@@ -0,0 +1,37 @@
+```java
+package io.opentdf.platform;
+
+import io.opentdf.platform.sdk.Config;
+import io.opentdf.platform.sdk.SDK;
+import io.opentdf.platform.sdk.SDKBuilder;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class DecryptCollectionExample {
+ public static void main(String[] args) throws IOException {
+ String clientId = "opentdf-sdk";
+ String clientSecret = "secret";
+ String platformEndpoint = "localhost:8080";
+
+ SDKBuilder builder = new SDKBuilder();
+ SDK sdk = builder.platformEndpoint(platformEndpoint)
+ .clientSecret(clientId, clientSecret).useInsecurePlaintextConnection(true)
+ .build();
+
+ var kasInfo = new Config.KASInfo();
+ kasInfo.URL = "http://localhost:8080/kas";
+
+
+ // Convert String to InputStream
+ for (int i = 0; i < 50; i++) {
+ FileInputStream fis = new FileInputStream(String.format("out/my.%d_ciphertext", i));
+ sdk.readNanoTDF(ByteBuffer.wrap(fis.readAllBytes()), System.out, Config.newNanoTDFReaderConfig());
+ fis.close();
+ }
+
+ }
+}
+
+```
\ No newline at end of file
diff --git a/code_samples/java/encrypt-collection-example.mdx b/code_samples/java/encrypt-collection-example.mdx
new file mode 100644
index 00000000..c65e0578
--- /dev/null
+++ b/code_samples/java/encrypt-collection-example.mdx
@@ -0,0 +1,42 @@
+```java
+package io.opentdf.platform;
+
+import io.opentdf.platform.sdk.Config;
+import io.opentdf.platform.sdk.SDK;
+import io.opentdf.platform.sdk.SDKBuilder;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+public class EncryptCollectionExample {
+ public static void main(String[] args) throws IOException {
+ String clientId = "opentdf-sdk";
+ String clientSecret = "secret";
+ String platformEndpoint = "localhost:8080";
+
+ SDKBuilder builder = new SDKBuilder();
+ SDK sdk = builder.platformEndpoint(platformEndpoint)
+ .clientSecret(clientId, clientSecret).useInsecurePlaintextConnection(true)
+ .build();
+
+ var kasInfo = new Config.KASInfo();
+ kasInfo.URL = "http://localhost:8080/kas";
+
+ var tdfConfig = Config.newNanoTDFConfig(
+ Config.withNanoKasInformation(kasInfo),
+ Config.witDataAttributes("https://example.com/attr/attr1/value/value1"),
+ Config.withCollection()
+ );
+
+ String str = "Hello, World!";
+
+ for (int i = 0; i < 50; i++) {
+ FileOutputStream fos = new FileOutputStream(String.format("out/my.%d_ciphertext", i));
+ sdk.createNanoTDF(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8)), fos, tdfConfig);
+ }
+ }
+}
+
+```
\ No newline at end of file
From 921890d8e61d269ffd6fd282ce753706c8f11ea1 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Sat, 14 Feb 2026 00:09:09 -0500
Subject: [PATCH 11/20] feat(docs): enhance OpenAPI docs and update marketing
homepage
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
OpenAPI Documentation Improvements:
- Add dynamic index generation that reads document IDs from generated files
- Rename .info.mdx files to index.mdx for cleaner sidebar navigation
- Create post-processing script for automated OpenAPI doc updates
- Fix sidebar.ts files no longer appearing as navigation items
Marketing Homepage Updates:
- Update hero subtitle copy for clarity and developer focus
- Fix broken links: /quickstart β /getting-started/quickstart
- Fix broken links: /category/concepts β /spec/concepts
- Fix broken links: /documentation β /introduction
- Update Architecture button link
- Update Specifications link to /spec
- Update Enterprise Solutions link to Virtru data security platform
- Remove Deployment Guides button
- Remove non-functional icons
Footer & Legal:
- Add license information to footer (Docs: CC BY 4.0, Code: BSD 3-Clause)
- Remove unused iconify-icon from copyright
Technical Changes:
- Add update-openapi-index npm script with post-generation hook
- Import gray-matter for frontmatter parsing
- Update vendored OpenAPI policy specs
Co-Authored-By: Claude Sonnet 4.5
---
docusaurus.config.ts | 15 +-
package.json | 3 +-
scripts/update-openapi-index.ts | 11 +
specs/policy/actions/actions.openapi.yaml | 23 --
.../policy/attributes/attributes.openapi.yaml | 23 --
.../policy/namespaces/namespaces.openapi.yaml | 179 --------------
specs/policy/objects.openapi.yaml | 23 --
.../obligations/obligations.openapi.yaml | 23 --
.../registered_resources.openapi.yaml | 23 --
.../resource_mapping.openapi.yaml | 23 --
.../subject_mapping.openapi.yaml | 23 --
specs/policy/unsafe/unsafe.openapi.yaml | 23 --
src/openapi/preprocessing.ts | 227 +++++++++++++++++-
src/pages/index.tsx | 85 ++++---
14 files changed, 296 insertions(+), 408 deletions(-)
create mode 100644 scripts/update-openapi-index.ts
diff --git a/docusaurus.config.ts b/docusaurus.config.ts
index cb8d5e40..363e2f0f 100644
--- a/docusaurus.config.ts
+++ b/docusaurus.config.ts
@@ -58,6 +58,12 @@ const config: Config = {
logo: "https://docs.opentdf.io/img/opentdf-social.png",
}),
},
+ {
+ tagName: "script",
+ attributes: {
+ src: "https://code.iconify.design/iconify-icon/2.1.0/iconify-icon.min.js",
+ },
+ },
],
onBrokenLinks: "throw",
@@ -198,8 +204,13 @@ const config: Config = {
},
],
copyright: `
- Copyright Β© ${new Date().getFullYear()} OpenTDF
-
+
+ Copyright Β© ${new Date().getFullYear()} OpenTDF
+
+
`,
},
prism: {
diff --git a/package.json b/package.json
index d116f7b2..c9ea89ca 100644
--- a/package.json
+++ b/package.json
@@ -12,8 +12,9 @@
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
- "gen-api-docs-all": "docusaurus gen-api-docs all --all-versions",
+ "gen-api-docs-all": "docusaurus gen-api-docs all --all-versions && npm run update-openapi-index",
"gen-api-docs-clean": "docusaurus clean-api-docs all",
+ "update-openapi-index": "tsx scripts/update-openapi-index.ts",
"check-vendored-yaml": "tsx src/openapi/check-vendored-yaml.ts",
"update-vendored-yaml": "tsx src/openapi/update-vendored-yaml.ts"
},
diff --git a/scripts/update-openapi-index.ts b/scripts/update-openapi-index.ts
new file mode 100644
index 00000000..9c8dd33a
--- /dev/null
+++ b/scripts/update-openapi-index.ts
@@ -0,0 +1,11 @@
+/**
+ * Post-processing script to update the OpenAPI index page with correct links
+ * after the OpenAPI docs have been generated.
+ */
+
+import { updateOpenApiIndex, renameInfoFilesToIndex } from '../src/openapi/preprocessing';
+
+console.log('π Running post-generation OpenAPI processing...');
+renameInfoFilesToIndex();
+updateOpenApiIndex();
+console.log('β
OpenAPI post-processing complete');
diff --git a/specs/policy/actions/actions.openapi.yaml b/specs/policy/actions/actions.openapi.yaml
index 9e04d4e3..a3efaf59 100644
--- a/specs/policy/actions/actions.openapi.yaml
+++ b/specs/policy/actions/actions.openapi.yaml
@@ -497,23 +497,6 @@ components:
required:
- rule
additionalProperties: false
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.Condition:
type: object
properties:
@@ -686,12 +669,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.Obligation:
diff --git a/specs/policy/attributes/attributes.openapi.yaml b/specs/policy/attributes/attributes.openapi.yaml
index aa04ee67..8788f9ef 100644
--- a/specs/policy/attributes/attributes.openapi.yaml
+++ b/specs/policy/attributes/attributes.openapi.yaml
@@ -1014,23 +1014,6 @@ components:
required:
- rule
additionalProperties: false
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.Condition:
type: object
properties:
@@ -1203,12 +1186,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.Obligation:
diff --git a/specs/policy/namespaces/namespaces.openapi.yaml b/specs/policy/namespaces/namespaces.openapi.yaml
index a32f5db1..51632ed0 100644
--- a/specs/policy/namespaces/namespaces.openapi.yaml
+++ b/specs/policy/namespaces/namespaces.openapi.yaml
@@ -325,77 +325,6 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/policy.namespaces.RemovePublicKeyFromNamespaceResponse'
- /policy.namespaces.NamespaceService/AssignCertificateToNamespace:
- post:
- tags:
- - policy.namespaces.NamespaceService
- summary: AssignCertificateToNamespace
- description: Namespace <> Certificate RPCs
- operationId: policy.namespaces.NamespaceService.AssignCertificateToNamespace
- parameters:
- - name: Connect-Protocol-Version
- in: header
- required: true
- schema:
- $ref: '#/components/schemas/connect-protocol-version'
- - name: Connect-Timeout-Ms
- in: header
- schema:
- $ref: '#/components/schemas/connect-timeout-header'
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/policy.namespaces.AssignCertificateToNamespaceRequest'
- required: true
- responses:
- default:
- description: Error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/connect.error'
- "200":
- description: Success
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/policy.namespaces.AssignCertificateToNamespaceResponse'
- /policy.namespaces.NamespaceService/RemoveCertificateFromNamespace:
- post:
- tags:
- - policy.namespaces.NamespaceService
- summary: RemoveCertificateFromNamespace
- operationId: policy.namespaces.NamespaceService.RemoveCertificateFromNamespace
- parameters:
- - name: Connect-Protocol-Version
- in: header
- required: true
- schema:
- $ref: '#/components/schemas/connect-protocol-version'
- - name: Connect-Timeout-Ms
- in: header
- schema:
- $ref: '#/components/schemas/connect-timeout-header'
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/policy.namespaces.RemoveCertificateFromNamespaceRequest'
- required: true
- responses:
- default:
- description: Error
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/connect.error'
- "200":
- description: Success
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/policy.namespaces.RemoveCertificateFromNamespaceResponse'
components:
schemas:
common.ActiveStateEnum:
@@ -446,20 +375,6 @@ components:
Describes whether this kas is managed by the organization or if they imported
the kas information from an external party. These two modes are necessary in order
to encrypt a tdf dek with an external parties kas public key.
- common.IdFqnIdentifier:
- type: object
- properties:
- id:
- type: string
- title: id
- format: uuid
- fqn:
- type: string
- title: fqn
- minLength: 1
- format: uri
- title: IdFqnIdentifier
- additionalProperties: false
common.Metadata:
type: object
properties:
@@ -620,23 +535,6 @@ components:
the Joda Time's [`ISODateTimeFormat.dateTime()`](
http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()
) to obtain a formatter capable of generating timestamps in this format.
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.KasPublicKey:
type: object
properties:
@@ -758,12 +656,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.PageRequest:
@@ -867,39 +759,6 @@ components:
title: pem
title: SimpleKasPublicKey
additionalProperties: false
- policy.namespaces.AssignCertificateToNamespaceRequest:
- type: object
- properties:
- namespace:
- title: namespace
- description: Required - namespace identifier (id or fqn)
- $ref: '#/components/schemas/common.IdFqnIdentifier'
- pem:
- type: string
- title: pem
- description: Required - PEM format certificate
- metadata:
- title: metadata
- description: Optional
- $ref: '#/components/schemas/common.MetadataMutable'
- title: AssignCertificateToNamespaceRequest
- required:
- - namespace
- - pem
- additionalProperties: false
- policy.namespaces.AssignCertificateToNamespaceResponse:
- type: object
- properties:
- namespaceCertificate:
- title: namespace_certificate
- description: The mapping of the namespace to the certificate.
- $ref: '#/components/schemas/policy.namespaces.NamespaceCertificate'
- certificate:
- title: certificate
- description: Return the full certificate object for convenience
- $ref: '#/components/schemas/policy.Certificate'
- title: AssignCertificateToNamespaceResponse
- additionalProperties: false
policy.namespaces.AssignKeyAccessServerToNamespaceRequest:
type: object
properties:
@@ -1057,24 +916,6 @@ components:
$ref: '#/components/schemas/policy.PageResponse'
title: ListNamespacesResponse
additionalProperties: false
- policy.namespaces.NamespaceCertificate:
- type: object
- properties:
- namespace:
- title: namespace
- description: Required - namespace identifier (id or fqn)
- $ref: '#/components/schemas/common.IdFqnIdentifier'
- certificateId:
- type: string
- title: certificate_id
- format: uuid
- description: Required (The id from the Certificate object)
- title: NamespaceCertificate
- required:
- - namespace
- - certificateId
- additionalProperties: false
- description: Maps a namespace to a certificate (similar to NamespaceKey pattern)
policy.namespaces.NamespaceKey:
type: object
properties:
@@ -1109,26 +950,6 @@ components:
title: NamespaceKeyAccessServer
additionalProperties: false
description: Deprecated
- policy.namespaces.RemoveCertificateFromNamespaceRequest:
- type: object
- properties:
- namespaceCertificate:
- title: namespace_certificate
- description: The namespace and certificate to unassign.
- $ref: '#/components/schemas/policy.namespaces.NamespaceCertificate'
- title: RemoveCertificateFromNamespaceRequest
- required:
- - namespaceCertificate
- additionalProperties: false
- policy.namespaces.RemoveCertificateFromNamespaceResponse:
- type: object
- properties:
- namespaceCertificate:
- title: namespace_certificate
- description: The unassigned namespace and certificate.
- $ref: '#/components/schemas/policy.namespaces.NamespaceCertificate'
- title: RemoveCertificateFromNamespaceResponse
- additionalProperties: false
policy.namespaces.RemoveKeyAccessServerFromNamespaceRequest:
type: object
properties:
diff --git a/specs/policy/objects.openapi.yaml b/specs/policy/objects.openapi.yaml
index 73ff1404..c1f082cc 100644
--- a/specs/policy/objects.openapi.yaml
+++ b/specs/policy/objects.openapi.yaml
@@ -355,23 +355,6 @@ components:
required:
- rule
additionalProperties: false
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.Condition:
type: object
properties:
@@ -605,12 +588,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.Obligation:
diff --git a/specs/policy/obligations/obligations.openapi.yaml b/specs/policy/obligations/obligations.openapi.yaml
index 904b7706..a0bc8c8c 100644
--- a/specs/policy/obligations/obligations.openapi.yaml
+++ b/specs/policy/obligations/obligations.openapi.yaml
@@ -846,23 +846,6 @@ components:
required:
- rule
additionalProperties: false
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.Condition:
type: object
properties:
@@ -1035,12 +1018,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.Obligation:
diff --git a/specs/policy/registeredresources/registered_resources.openapi.yaml b/specs/policy/registeredresources/registered_resources.openapi.yaml
index 0a481f4c..676ab81a 100644
--- a/specs/policy/registeredresources/registered_resources.openapi.yaml
+++ b/specs/policy/registeredresources/registered_resources.openapi.yaml
@@ -707,23 +707,6 @@ components:
required:
- rule
additionalProperties: false
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.Condition:
type: object
properties:
@@ -896,12 +879,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.Obligation:
diff --git a/specs/policy/resourcemapping/resource_mapping.openapi.yaml b/specs/policy/resourcemapping/resource_mapping.openapi.yaml
index 69cdbc4a..86b0d952 100644
--- a/specs/policy/resourcemapping/resource_mapping.openapi.yaml
+++ b/specs/policy/resourcemapping/resource_mapping.openapi.yaml
@@ -707,23 +707,6 @@ components:
required:
- rule
additionalProperties: false
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.Condition:
type: object
properties:
@@ -896,12 +879,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.Obligation:
diff --git a/specs/policy/subjectmapping/subject_mapping.openapi.yaml b/specs/policy/subjectmapping/subject_mapping.openapi.yaml
index 4d0e7f1b..f8dcc5ba 100644
--- a/specs/policy/subjectmapping/subject_mapping.openapi.yaml
+++ b/specs/policy/subjectmapping/subject_mapping.openapi.yaml
@@ -743,23 +743,6 @@ components:
required:
- rule
additionalProperties: false
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.Condition:
type: object
properties:
@@ -932,12 +915,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.Obligation:
diff --git a/specs/policy/unsafe/unsafe.openapi.yaml b/specs/policy/unsafe/unsafe.openapi.yaml
index c604fa65..bf346f58 100644
--- a/specs/policy/unsafe/unsafe.openapi.yaml
+++ b/specs/policy/unsafe/unsafe.openapi.yaml
@@ -721,23 +721,6 @@ components:
required:
- rule
additionalProperties: false
- policy.Certificate:
- type: object
- properties:
- id:
- type: string
- title: id
- description: generated uuid in database
- pem:
- type: string
- title: pem
- description: PEM format certificate
- metadata:
- title: metadata
- description: Optional metadata.
- $ref: '#/components/schemas/common.Metadata'
- title: Certificate
- additionalProperties: false
policy.Condition:
type: object
properties:
@@ -946,12 +929,6 @@ components:
$ref: '#/components/schemas/policy.SimpleKasKey'
title: kas_keys
description: Keys for the namespace
- rootCerts:
- type: array
- items:
- $ref: '#/components/schemas/policy.Certificate'
- title: root_certs
- description: Root certificates for chain of trust
title: Namespace
additionalProperties: false
policy.Obligation:
diff --git a/src/openapi/preprocessing.ts b/src/openapi/preprocessing.ts
index 1e410980..1b636119 100644
--- a/src/openapi/preprocessing.ts
+++ b/src/openapi/preprocessing.ts
@@ -4,6 +4,7 @@ When making changes to this file, consider: https://virtru.atlassian.net/browse/
import * as fs from 'fs';
import * as path from 'path';
import * as yaml from 'js-yaml';
+import matter from 'gray-matter';
import type * as OpenApiPlugin from "docusaurus-plugin-openapi-docs";
// Utility to find the repo root (directory containing package.json)
@@ -414,16 +415,101 @@ async function preprocessOpenApiSpecs() {
delete spec.specPathModified;
}
- // Create the index page for OpenAPI documentation
+ // Create the index page for OpenAPI documentation with auto-generated service links
+
+ // Helper function to find and read the document ID from a generated .info.mdx file
+ function getDocIdFromInfoFile(outputDir: string): string | null {
+ try {
+ // Find .info.mdx files in the output directory
+ const files = fs.readdirSync(outputDir);
+ const infoFile = files.find(f => f.endsWith('.info.mdx'));
+
+ if (infoFile) {
+ const infoPath = path.join(outputDir, infoFile);
+ const fileContent = fs.readFileSync(infoPath, 'utf8');
+ const parsed = matter(fileContent);
+
+ if (parsed.data.id) {
+ // Return the full document path
+ const relativePath = path.relative(OUTPUT_PREFIX, outputDir);
+ return `OpenAPI-clients/${relativePath}/${parsed.data.id}`;
+ }
+ }
+ } catch (error) {
+ console.warn(`β οΈ Could not read info file from ${outputDir}: ${error}`);
+ }
+ return null;
+ }
+
+ // Service descriptions - can be customized per service
+ const serviceDescriptions: Record = {
+ 'Well-Known Configuration': 'Platform configuration and service discovery',
+ 'kas': 'Key Access Service for TDF encryption/decryption',
+ 'V1 Authorization': 'Authorization decisions (v1)',
+ 'V2 Authorization': 'Authorization decisions (v2)',
+ 'V1 Entity Resolution': 'Entity resolution from JWT tokens (v1)',
+ 'V2 Entity Resolution': 'Entity resolution from tokens (v2)',
+ 'Policy Objects': 'Core policy objects and management',
+ 'Policy Attributes': 'Attribute definitions and values',
+ 'Policy Namespaces': 'Namespace management',
+ 'Policy Actions': 'Action definitions',
+ 'Policy Subject Mapping': 'Map subjects to attributes',
+ 'Policy Resource Mapping': 'Map resources to attributes',
+ 'Policy Obligations': 'Usage obligations and triggers',
+ 'Policy Registered Resources': 'Resource registration',
+ 'Policy KAS Registry': 'KAS registration and management',
+ 'Key Management': 'Cryptographic key management',
+ 'Policy Unsafe Service': 'Administrative operations',
+ };
+
+ // Categorization - define which specs belong to which category
+ const categoryMapping: Record = {
+ 'Core Services': ['Well-Known Configuration', 'kas'],
+ 'Authorization & Entity Resolution': ['V1 Authorization', 'V2 Authorization', 'V1 Entity Resolution', 'V2 Entity Resolution'],
+ 'Policy Management': ['Policy Objects', 'Policy Attributes', 'Policy Namespaces', 'Policy Actions',
+ 'Policy Subject Mapping', 'Policy Resource Mapping', 'Policy Obligations',
+ 'Policy Registered Resources', 'Policy KAS Registry', 'Key Management', 'Policy Unsafe Service'],
+ };
+
+ // Build service links dynamically from openApiSpecsArray
+ let serviceLinksMarkdown = '';
+ Object.entries(categoryMapping).forEach(([category, specIds]) => {
+ serviceLinksMarkdown += `\n## ${category}\n\n`;
+ specIds.forEach(specId => {
+ const spec = openApiSpecsArray.find(s => s.id === specId);
+ if (spec) {
+ // Try to read the document ID from the generated .info.mdx file
+ const docId = getDocIdFromInfoFile(spec.outputDir);
+ if (docId) {
+ const description = serviceDescriptions[specId] || 'API documentation';
+ serviceLinksMarkdown += `- **[${spec.id}](/${docId})** - ${description}\n`;
+ } else {
+ console.warn(`β οΈ Could not generate link for ${spec.id} - .info.mdx file not found yet`);
+ }
+ }
+ });
+ });
+
const indexContent = `---
title: OpenAPI Clients
sidebar_position: 7
---
# OpenAPI Clients
-OpenAPI client examples are available for platform endpoints.
+Interactive API documentation for OpenTDF Platform services. Each endpoint includes request/response examples, parameter descriptions, and the ability to try requests directly in your browser.
+
+${serviceLinksMarkdown}
+
+## Getting Started
+
+1. Select a service from the list above or navigation sidebar
+2. Browse available endpoints and operations
+3. Review request parameters and response schemas
+4. Test endpoints using the "Try it" feature
+
+## Authentication
-Expand each section in the navigation panel to access the OpenAPI documentation for each service.
+Most endpoints require authentication. Configure your access token in the API documentation interface before testing endpoints.
`
// Ensure the file 'OPENAPI_INDEX_PAGE' exists
@@ -436,5 +522,138 @@ Expand each section in the navigation panel to access the OpenAPI documentation
};
+/**
+ * Renames all .info.mdx files to index.mdx so they become category index pages
+ * instead of appearing as separate items in the sidebar.
+ */
+function renameInfoFilesToIndex() {
+ console.log('π Renaming .info.mdx files to index.mdx...');
+
+ function processDirectory(dir: string) {
+ if (!fs.existsSync(dir)) return;
+
+ const items = fs.readdirSync(dir, { withFileTypes: true });
+
+ for (const item of items) {
+ const fullPath = path.join(dir, item.name);
+
+ if (item.isDirectory()) {
+ processDirectory(fullPath);
+ } else if (item.name.endsWith('.info.mdx')) {
+ const newPath = path.join(dir, 'index.mdx');
+ fs.renameSync(fullPath, newPath);
+ console.log(` Renamed: ${fullPath} β ${newPath}`);
+ }
+ }
+ }
+
+ processDirectory(OUTPUT_PREFIX);
+ console.log('β
Renamed all .info.mdx files to index.mdx');
+}
+
+/**
+ * Updates the OpenAPI index page with links to generated docs.
+ * This should be called AFTER the OpenAPI docs have been generated.
+ */
+function updateOpenApiIndex() {
+ console.log('π Updating OpenAPI index page with generated doc links...');
+
+ // Service descriptions - can be customized per service
+ const serviceDescriptions: Record = {
+ 'Well-Known Configuration': 'Platform configuration and service discovery',
+ 'kas': 'Key Access Service for TDF encryption/decryption',
+ 'V1 Authorization': 'Authorization decisions (v1)',
+ 'V2 Authorization': 'Authorization decisions (v2)',
+ 'V1 Entity Resolution': 'Entity resolution from JWT tokens (v1)',
+ 'V2 Entity Resolution': 'Entity resolution from tokens (v2)',
+ 'Policy Objects': 'Core policy objects and management',
+ 'Policy Attributes': 'Attribute definitions and values',
+ 'Policy Namespaces': 'Namespace management',
+ 'Policy Actions': 'Action definitions',
+ 'Policy Subject Mapping': 'Map subjects to attributes',
+ 'Policy Resource Mapping': 'Map resources to attributes',
+ 'Policy Obligations': 'Usage obligations and triggers',
+ 'Policy Registered Resources': 'Resource registration',
+ 'Policy KAS Registry': 'KAS registration and management',
+ 'Key Management': 'Cryptographic key management',
+ 'Policy Unsafe Service': 'Administrative operations',
+ };
+
+ // Categorization
+ const categoryMapping: Record = {
+ 'Core Services': ['Well-Known Configuration', 'kas'],
+ 'Authorization & Entity Resolution': ['V1 Authorization', 'V2 Authorization', 'V1 Entity Resolution', 'V2 Entity Resolution'],
+ 'Policy Management': ['Policy Objects', 'Policy Attributes', 'Policy Namespaces', 'Policy Actions',
+ 'Policy Subject Mapping', 'Policy Resource Mapping', 'Policy Obligations',
+ 'Policy Registered Resources', 'Policy KAS Registry', 'Key Management', 'Policy Unsafe Service'],
+ };
+
+ // Helper function to find and read the document ID from a generated index.mdx file
+ function getDocIdFromInfoFile(outputDir: string): string | null {
+ try {
+ if (!fs.existsSync(outputDir)) {
+ return null;
+ }
+
+ const indexPath = path.join(outputDir, 'index.mdx');
+
+ if (fs.existsSync(indexPath)) {
+ const fileContent = fs.readFileSync(indexPath, 'utf8');
+ const parsed = matter(fileContent);
+
+ if (parsed.data.id) {
+ const relativePath = path.relative(OUTPUT_PREFIX, outputDir);
+ return `OpenAPI-clients/${relativePath}/${parsed.data.id}`;
+ }
+ }
+ } catch (error) {
+ // Silently skip if file doesn't exist yet
+ }
+ return null;
+ }
+
+ // Build service links dynamically from openApiSpecsArray
+ let serviceLinksMarkdown = '';
+ Object.entries(categoryMapping).forEach(([category, specIds]) => {
+ serviceLinksMarkdown += `\n## ${category}\n\n`;
+ specIds.forEach(specId => {
+ const spec = openApiSpecsArray.find(s => s.id === specId);
+ if (spec) {
+ const docId = getDocIdFromInfoFile(spec.outputDir);
+ if (docId) {
+ const description = serviceDescriptions[specId] || 'API documentation';
+ serviceLinksMarkdown += `- **[${spec.id}](/${docId})** - ${description}\n`;
+ }
+ }
+ });
+ });
+
+ const indexContent = `---
+title: OpenAPI Clients
+sidebar_position: 7
+---
+# OpenAPI Clients
+
+Interactive API documentation for OpenTDF Platform services. Each endpoint includes request/response examples, parameter descriptions, and the ability to try requests directly in your browser.
+
+${serviceLinksMarkdown}
+
+## Getting Started
+
+1. Select a service from the list above or navigation sidebar
+2. Browse available endpoints and operations
+3. Review request parameters and response schemas
+4. Test endpoints using the "Try it" feature
+
+## Authentication
+
+Most endpoints require authentication. Configure your access token in the API documentation interface before testing endpoints.
+`;
+
+ fs.mkdirSync(path.dirname(OPENAPI_INDEX_PAGE), { recursive: true });
+ fs.writeFileSync(OPENAPI_INDEX_PAGE, indexContent, 'utf8');
+ console.log(`β
Updated OpenAPI index page at ${OPENAPI_INDEX_PAGE}`);
+}
+
// Export the function and data without automatically executing it
-export { openApiSpecs, openApiSpecsArray, preprocessOpenApiSpecs };
\ No newline at end of file
+export { openApiSpecs, openApiSpecsArray, preprocessOpenApiSpecs, updateOpenApiIndex, renameInfoFilesToIndex };
\ No newline at end of file
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index e4f00d40..52c2c722 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -19,24 +19,27 @@ export default function Home() {
Protect the Data, Build the Future
- Zero-trust data protection that travels with your data wherever it goes.
- OpenTDF cryptographically binds access control policies directly to data objects,
- ensuring your data remains secure regardless of network boundaries or storage location.
+ Open-source data-centric security for developers. OpenTDF delivers the Trusted Data Format (TDF) specification,
+ foundational services for key management and access control, and SDKs β the building blocks to cryptographically
+ bind protection directly to your data, wherever it goes.
+
+
+ Explore the standard. Prototype custom applications. Build architectures where security travels with the data, not the network.
@@ -50,24 +53,34 @@ export default function Home() {
Traditional Security Fails When Data Leaves the Perimeter
- Once data crosses network boundaries, traditional security models lose control.
- OpenTDF solves this by cryptographically binding policies to data objects themselves,
- creating self-protecting data that enforces access controls anywhere it travels.
+ Firewalls, VPNs, and network policies protect the boundary β not the data.
+ The moment a file is shared, downloaded, or moved to a new environment,
+ those controls vanish. Access decisions remain at the perimeter, while the
+ data moves on without them.
+
+
+ OpenTDF inverts this model. Policies travel with the data itself, so you can:
+
+ - Revoke access after sharing β even after data has left your environment
+ - Enforce controls in zero-trust environments β no VPN, no network dependency
+ - Maintain a complete audit trail β know who accessed what, when, and where
+
+ This is data-centric security: protection that's embedded, not bolted on.
@@ -86,19 +99,19 @@ export default function Home() {
secure applications without sacrificing speed or simplicity.
@@ -117,19 +130,15 @@ export default function Home() {
to government and defense. Battle-tested, enterprise-ready, open source.
@@ -148,19 +157,19 @@ export default function Home() {
ensuring your data protection strategy is future-proof and audit-ready.
@@ -180,18 +189,18 @@ export default function Home() {
@@ -208,16 +217,16 @@ export default function Home() {
Choose your path and start building with OpenTDF today.
From d6cc85041e38ab7d215dc964f5e902316582a128 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Sat, 14 Feb 2026 00:27:25 -0500
Subject: [PATCH 12/20] Add Surge info back
---
README.md | 53 +++++++++++++++++++----------------------------------
1 file changed, 19 insertions(+), 34 deletions(-)
diff --git a/README.md b/README.md
index dab22880..8627ebb5 100644
--- a/README.md
+++ b/README.md
@@ -15,15 +15,6 @@ OpenTDF is an open source system for implementing data-centric security that ena
- **Policy Travels with Data**: Security controls remain attached wherever data goes
- **Trust Data Format (TDF)**: Open standard for self-protecting data
-## Documentation Structure
-
-Our documentation follows a user-needs approach with four main categories:
-
-- **π Tutorials**: Step-by-step learning experiences for hands-on practice
-- **π How-To Guides**: Problem-solving recipes for specific tasks and integrations
-- **π‘ Explanations**: Conceptual guides covering the "why" behind OpenTDF's design
-- **π Reference**: Technical specifications, API docs, and lookup information
-
## Contributing
We welcome contributions to improve our documentation! Please see our [Contributing Guide](CONTRIBUTING.md) for guidelines on:
@@ -33,8 +24,6 @@ We welcome contributions to improve our documentation! Please see our [Contribut
- Review and approval process
- Technical setup for contributors
-For style guidelines, please refer to our [Style Guide](STYLE_GUIDE.md).
-
## Quick Links
- **Live Documentation**: [docs.opentdf.io](https://docs.opentdf.io)
@@ -126,40 +115,34 @@ This command starts a local development server and opens up a browser window. Mo
This command generates static content into the `build` directory and can be served using any static contents hosting service.
-### Testing with Feature Branches
+### Preview Deployment
-The documentation site pulls content from multiple upstream repositories using Docusaurus remote content plugins. By default, content is fetched from the `main` branch of each repository. You can override this behavior using environment variables to test documentation changes from feature branches before they're merged.
+Deploy to a Surge preview domain for testing changes before merging to production. **A free Surge account is required** - you'll be prompted to sign up the first time you deploy.
-**Available Environment Variables:**
+**Important:** Each developer should use a unique preview domain name to avoid conflicts. Use a descriptive name based on your ticket number or feature:
-- `PLATFORM_BRANCH` - Controls which branch to fetch from `opentdf/platform` (default: `main`)
-- `SPEC_BRANCH` - Controls which branch to fetch from `opentdf/spec` (default: `main`)
-- `OTDFCTL_BRANCH` - Controls which branch to fetch from `opentdf/otdfctl` (default: `main`)
-
-**Examples:**
-
-Test with all feature branches:
```bash
-PLATFORM_BRANCH=jps-updates SPEC_BRANCH=jps-updates OTDFCTL_BRANCH=jps-updates npm run build
-```
+# Build the site
+npm run build
-Test with a single feature branch:
-```bash
-SPEC_BRANCH=feature-branch-name npm run build
+# Deploy to your unique preview URL
+# Replace with your ticket number or feature name
+npx surge build opentdf-docs-preview-.surge.sh
```
-Test in development mode with feature branches:
+**Examples:**
+
```bash
-PLATFORM_BRANCH=my-feature npm run start
-```
+# Using ticket number
+npx surge build opentdf-docs-preview-dspx-2345.surge.sh
-**Use Cases:**
+# Using feature description
+npx surge build opentdf-docs-preview-troubleshooting-updates.surge.sh
+```
-- **Before merging PRs**: Test how documentation changes from upstream repos will look when integrated
-- **Cross-repo changes**: When making coordinated changes across multiple repositories, test the full integration locally
-- **Debugging**: Investigate issues with specific branches without affecting your local main branch
+Your preview will be available at `https://opentdf-docs-preview-.surge.sh/`
-**Note**: The branches must exist in the respective GitHub repositories and be accessible (public or you have access).
+**Note:** The first time you deploy, Surge will prompt you to create a free account or login.
---
@@ -172,10 +155,12 @@ This documentation is licensed under the [Creative Commons Attribution 4.0 Inter
**Effective Date: February 13, 2026**
This project's documentation license has changed from:
+
- **Previous:** Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
- **New:** Creative Commons Attribution 4.0 International (CC BY 4.0)
**What this means:**
+
- β
You can use, adapt, and share this documentation under any terms
- β
You only need to provide attribution to the original work
- β
No longer required to share derivative works under the same license (ShareAlike requirement removed)
From b21943d398f24d99ae7816241e1a1f1556e26cb4 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Sat, 14 Feb 2026 00:29:46 -0500
Subject: [PATCH 13/20] chore: remove Java collection examples from PR
These files were auto-generated and should not be included in this PR.
Co-Authored-By: Claude Sonnet 4.5
---
.../java/decrypt-collection-example.mdx | 37 ----------------
.../java/encrypt-collection-example.mdx | 42 -------------------
2 files changed, 79 deletions(-)
delete mode 100644 code_samples/java/decrypt-collection-example.mdx
delete mode 100644 code_samples/java/encrypt-collection-example.mdx
diff --git a/code_samples/java/decrypt-collection-example.mdx b/code_samples/java/decrypt-collection-example.mdx
deleted file mode 100644
index 05731c6f..00000000
--- a/code_samples/java/decrypt-collection-example.mdx
+++ /dev/null
@@ -1,37 +0,0 @@
-```java
-package io.opentdf.platform;
-
-import io.opentdf.platform.sdk.Config;
-import io.opentdf.platform.sdk.SDK;
-import io.opentdf.platform.sdk.SDKBuilder;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-public class DecryptCollectionExample {
- public static void main(String[] args) throws IOException {
- String clientId = "opentdf-sdk";
- String clientSecret = "secret";
- String platformEndpoint = "localhost:8080";
-
- SDKBuilder builder = new SDKBuilder();
- SDK sdk = builder.platformEndpoint(platformEndpoint)
- .clientSecret(clientId, clientSecret).useInsecurePlaintextConnection(true)
- .build();
-
- var kasInfo = new Config.KASInfo();
- kasInfo.URL = "http://localhost:8080/kas";
-
-
- // Convert String to InputStream
- for (int i = 0; i < 50; i++) {
- FileInputStream fis = new FileInputStream(String.format("out/my.%d_ciphertext", i));
- sdk.readNanoTDF(ByteBuffer.wrap(fis.readAllBytes()), System.out, Config.newNanoTDFReaderConfig());
- fis.close();
- }
-
- }
-}
-
-```
\ No newline at end of file
diff --git a/code_samples/java/encrypt-collection-example.mdx b/code_samples/java/encrypt-collection-example.mdx
deleted file mode 100644
index c65e0578..00000000
--- a/code_samples/java/encrypt-collection-example.mdx
+++ /dev/null
@@ -1,42 +0,0 @@
-```java
-package io.opentdf.platform;
-
-import io.opentdf.platform.sdk.Config;
-import io.opentdf.platform.sdk.SDK;
-import io.opentdf.platform.sdk.SDKBuilder;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-
-public class EncryptCollectionExample {
- public static void main(String[] args) throws IOException {
- String clientId = "opentdf-sdk";
- String clientSecret = "secret";
- String platformEndpoint = "localhost:8080";
-
- SDKBuilder builder = new SDKBuilder();
- SDK sdk = builder.platformEndpoint(platformEndpoint)
- .clientSecret(clientId, clientSecret).useInsecurePlaintextConnection(true)
- .build();
-
- var kasInfo = new Config.KASInfo();
- kasInfo.URL = "http://localhost:8080/kas";
-
- var tdfConfig = Config.newNanoTDFConfig(
- Config.withNanoKasInformation(kasInfo),
- Config.witDataAttributes("https://example.com/attr/attr1/value/value1"),
- Config.withCollection()
- );
-
- String str = "Hello, World!";
-
- for (int i = 0; i < 50; i++) {
- FileOutputStream fos = new FileOutputStream(String.format("out/my.%d_ciphertext", i));
- sdk.createNanoTDF(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8)), fos, tdfConfig);
- }
- }
-}
-
-```
\ No newline at end of file
From 4009abb42b2ecb9f8e2111110624127d73575b65 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Sat, 14 Feb 2026 00:32:23 -0500
Subject: [PATCH 14/20] chore: add CC-BY-4.0 license to package.json
Add SPDX license identifier to help GitHub recognize the Creative Commons
license for documentation.
Co-Authored-By: Claude Sonnet 4.5
---
package.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/package.json b/package.json
index c9ea89ca..b73b0a8d 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
"name": "docs",
"version": "0.0.0",
"private": true,
+ "license": "CC-BY-4.0",
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
From a771890b5e237a7f6a770df13463d19b847bb508 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Sat, 14 Feb 2026 00:36:38 -0500
Subject: [PATCH 15/20] refactor: address code review feedback
- Remove unused styles import from index.tsx
- Extract SERVICE_DESCRIPTIONS and CATEGORY_MAPPING constants to reduce
code duplication in preprocessing.ts
- Both preprocessOpenApiSpecs and updateOpenApiIndex now use shared constants
Addresses Gemini Code Assist review comments about maintainability.
Co-Authored-By: Claude Sonnet 4.5
---
src/openapi/preprocessing.ts | 97 ++++++++++++------------------------
src/pages/index.tsx | 1 -
2 files changed, 33 insertions(+), 65 deletions(-)
diff --git a/src/openapi/preprocessing.ts b/src/openapi/preprocessing.ts
index 1b636119..21e75154 100644
--- a/src/openapi/preprocessing.ts
+++ b/src/openapi/preprocessing.ts
@@ -31,6 +31,35 @@ const OUTPUT_PREFIX = path.join(repoRoot, 'docs', 'OpenAPI-clients');
// The index page for OpenAPI documentation, to support bookmarking & sharing the URL
const OPENAPI_INDEX_PAGE = `${OUTPUT_PREFIX}/index.md`;
+// Service descriptions and categorization for OpenAPI index generation
+const SERVICE_DESCRIPTIONS: Record = {
+ 'Well-Known Configuration': 'Platform configuration and service discovery',
+ 'kas': 'Key Access Service for TDF encryption/decryption',
+ 'V1 Authorization': 'Authorization decisions (v1)',
+ 'V2 Authorization': 'Authorization decisions (v2)',
+ 'V1 Entity Resolution': 'Entity resolution from JWT tokens (v1)',
+ 'V2 Entity Resolution': 'Entity resolution from tokens (v2)',
+ 'Policy Objects': 'Core policy objects and management',
+ 'Policy Attributes': 'Attribute definitions and values',
+ 'Policy Namespaces': 'Namespace management',
+ 'Policy Actions': 'Action definitions',
+ 'Policy Subject Mapping': 'Map subjects to attributes',
+ 'Policy Resource Mapping': 'Map resources to attributes',
+ 'Policy Obligations': 'Usage obligations and triggers',
+ 'Policy Registered Resources': 'Resource registration',
+ 'Policy KAS Registry': 'KAS registration and management',
+ 'Key Management': 'Cryptographic key management',
+ 'Policy Unsafe Service': 'Administrative operations',
+};
+
+const CATEGORY_MAPPING: Record = {
+ 'Core Services': ['Well-Known Configuration', 'kas'],
+ 'Authorization & Entity Resolution': ['V1 Authorization', 'V2 Authorization', 'V1 Entity Resolution', 'V2 Entity Resolution'],
+ 'Policy Management': ['Policy Objects', 'Policy Attributes', 'Policy Namespaces', 'Policy Actions',
+ 'Policy Subject Mapping', 'Policy Resource Mapping', 'Policy Obligations',
+ 'Policy Registered Resources', 'Policy KAS Registry', 'Key Management', 'Policy Unsafe Service'],
+};
+
// Read BUILD_OPENAPI_SAMPLES once
const BUILD_OPENAPI_SAMPLES = process.env.BUILD_OPENAPI_SAMPLES === '1';
@@ -441,39 +470,9 @@ async function preprocessOpenApiSpecs() {
return null;
}
- // Service descriptions - can be customized per service
- const serviceDescriptions: Record = {
- 'Well-Known Configuration': 'Platform configuration and service discovery',
- 'kas': 'Key Access Service for TDF encryption/decryption',
- 'V1 Authorization': 'Authorization decisions (v1)',
- 'V2 Authorization': 'Authorization decisions (v2)',
- 'V1 Entity Resolution': 'Entity resolution from JWT tokens (v1)',
- 'V2 Entity Resolution': 'Entity resolution from tokens (v2)',
- 'Policy Objects': 'Core policy objects and management',
- 'Policy Attributes': 'Attribute definitions and values',
- 'Policy Namespaces': 'Namespace management',
- 'Policy Actions': 'Action definitions',
- 'Policy Subject Mapping': 'Map subjects to attributes',
- 'Policy Resource Mapping': 'Map resources to attributes',
- 'Policy Obligations': 'Usage obligations and triggers',
- 'Policy Registered Resources': 'Resource registration',
- 'Policy KAS Registry': 'KAS registration and management',
- 'Key Management': 'Cryptographic key management',
- 'Policy Unsafe Service': 'Administrative operations',
- };
-
- // Categorization - define which specs belong to which category
- const categoryMapping: Record = {
- 'Core Services': ['Well-Known Configuration', 'kas'],
- 'Authorization & Entity Resolution': ['V1 Authorization', 'V2 Authorization', 'V1 Entity Resolution', 'V2 Entity Resolution'],
- 'Policy Management': ['Policy Objects', 'Policy Attributes', 'Policy Namespaces', 'Policy Actions',
- 'Policy Subject Mapping', 'Policy Resource Mapping', 'Policy Obligations',
- 'Policy Registered Resources', 'Policy KAS Registry', 'Key Management', 'Policy Unsafe Service'],
- };
-
// Build service links dynamically from openApiSpecsArray
let serviceLinksMarkdown = '';
- Object.entries(categoryMapping).forEach(([category, specIds]) => {
+ Object.entries(CATEGORY_MAPPING).forEach(([category, specIds]) => {
serviceLinksMarkdown += `\n## ${category}\n\n`;
specIds.forEach(specId => {
const spec = openApiSpecsArray.find(s => s.id === specId);
@@ -481,7 +480,7 @@ async function preprocessOpenApiSpecs() {
// Try to read the document ID from the generated .info.mdx file
const docId = getDocIdFromInfoFile(spec.outputDir);
if (docId) {
- const description = serviceDescriptions[specId] || 'API documentation';
+ const description = SERVICE_DESCRIPTIONS[specId] || 'API documentation';
serviceLinksMarkdown += `- **[${spec.id}](/${docId})** - ${description}\n`;
} else {
console.warn(`β οΈ Could not generate link for ${spec.id} - .info.mdx file not found yet`);
@@ -558,36 +557,6 @@ function renameInfoFilesToIndex() {
function updateOpenApiIndex() {
console.log('π Updating OpenAPI index page with generated doc links...');
- // Service descriptions - can be customized per service
- const serviceDescriptions: Record = {
- 'Well-Known Configuration': 'Platform configuration and service discovery',
- 'kas': 'Key Access Service for TDF encryption/decryption',
- 'V1 Authorization': 'Authorization decisions (v1)',
- 'V2 Authorization': 'Authorization decisions (v2)',
- 'V1 Entity Resolution': 'Entity resolution from JWT tokens (v1)',
- 'V2 Entity Resolution': 'Entity resolution from tokens (v2)',
- 'Policy Objects': 'Core policy objects and management',
- 'Policy Attributes': 'Attribute definitions and values',
- 'Policy Namespaces': 'Namespace management',
- 'Policy Actions': 'Action definitions',
- 'Policy Subject Mapping': 'Map subjects to attributes',
- 'Policy Resource Mapping': 'Map resources to attributes',
- 'Policy Obligations': 'Usage obligations and triggers',
- 'Policy Registered Resources': 'Resource registration',
- 'Policy KAS Registry': 'KAS registration and management',
- 'Key Management': 'Cryptographic key management',
- 'Policy Unsafe Service': 'Administrative operations',
- };
-
- // Categorization
- const categoryMapping: Record = {
- 'Core Services': ['Well-Known Configuration', 'kas'],
- 'Authorization & Entity Resolution': ['V1 Authorization', 'V2 Authorization', 'V1 Entity Resolution', 'V2 Entity Resolution'],
- 'Policy Management': ['Policy Objects', 'Policy Attributes', 'Policy Namespaces', 'Policy Actions',
- 'Policy Subject Mapping', 'Policy Resource Mapping', 'Policy Obligations',
- 'Policy Registered Resources', 'Policy KAS Registry', 'Key Management', 'Policy Unsafe Service'],
- };
-
// Helper function to find and read the document ID from a generated index.mdx file
function getDocIdFromInfoFile(outputDir: string): string | null {
try {
@@ -614,14 +583,14 @@ function updateOpenApiIndex() {
// Build service links dynamically from openApiSpecsArray
let serviceLinksMarkdown = '';
- Object.entries(categoryMapping).forEach(([category, specIds]) => {
+ Object.entries(CATEGORY_MAPPING).forEach(([category, specIds]) => {
serviceLinksMarkdown += `\n## ${category}\n\n`;
specIds.forEach(specId => {
const spec = openApiSpecsArray.find(s => s.id === specId);
if (spec) {
const docId = getDocIdFromInfoFile(spec.outputDir);
if (docId) {
- const description = serviceDescriptions[specId] || 'API documentation';
+ const description = SERVICE_DESCRIPTIONS[specId] || 'API documentation';
serviceLinksMarkdown += `- **[${spec.id}](/${docId})** - ${description}\n`;
}
}
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 52c2c722..e1861f9d 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,7 +1,6 @@
import React from "react";
import Layout from "@theme/Layout";
import Head from "@docusaurus/Head";
-import styles from "./index.module.css";
export default function Home() {
return (
From 52717fa29aa06875344c6813b69de5a499580bce Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Sat, 14 Feb 2026 00:38:06 -0500
Subject: [PATCH 16/20] feat: add catch-all category for uncategorized APIs
- Automatically detect APIs not in CATEGORY_MAPPING
- Add them to "Other APIs" category
- Log warning with list of uncategorized API names
- Prevents new APIs from being silently omitted from index
Co-Authored-By: Claude Sonnet 4.5
---
src/openapi/preprocessing.ts | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/src/openapi/preprocessing.ts b/src/openapi/preprocessing.ts
index 21e75154..32984cf3 100644
--- a/src/openapi/preprocessing.ts
+++ b/src/openapi/preprocessing.ts
@@ -471,10 +471,14 @@ async function preprocessOpenApiSpecs() {
}
// Build service links dynamically from openApiSpecsArray
+ // Track which specs are categorized to find uncategorized ones
+ const categorizedSpecs = new Set();
let serviceLinksMarkdown = '';
+
Object.entries(CATEGORY_MAPPING).forEach(([category, specIds]) => {
serviceLinksMarkdown += `\n## ${category}\n\n`;
specIds.forEach(specId => {
+ categorizedSpecs.add(specId);
const spec = openApiSpecsArray.find(s => s.id === specId);
if (spec) {
// Try to read the document ID from the generated .info.mdx file
@@ -489,6 +493,20 @@ async function preprocessOpenApiSpecs() {
});
});
+ // Add uncategorized APIs to a catch-all category
+ const uncategorizedSpecs = openApiSpecsArray.filter(spec => !categorizedSpecs.has(spec.id));
+ if (uncategorizedSpecs.length > 0) {
+ console.warn(`β οΈ Found ${uncategorizedSpecs.length} uncategorized API(s): ${uncategorizedSpecs.map(s => s.id).join(', ')}`);
+ serviceLinksMarkdown += `\n## Other APIs\n\n`;
+ uncategorizedSpecs.forEach(spec => {
+ const docId = getDocIdFromInfoFile(spec.outputDir);
+ if (docId) {
+ const description = SERVICE_DESCRIPTIONS[spec.id] || 'API documentation';
+ serviceLinksMarkdown += `- **[${spec.id}](/${docId})** - ${description}\n`;
+ }
+ });
+ }
+
const indexContent = `---
title: OpenAPI Clients
sidebar_position: 7
@@ -582,10 +600,14 @@ function updateOpenApiIndex() {
}
// Build service links dynamically from openApiSpecsArray
+ // Track which specs are categorized to find uncategorized ones
+ const categorizedSpecs = new Set();
let serviceLinksMarkdown = '';
+
Object.entries(CATEGORY_MAPPING).forEach(([category, specIds]) => {
serviceLinksMarkdown += `\n## ${category}\n\n`;
specIds.forEach(specId => {
+ categorizedSpecs.add(specId);
const spec = openApiSpecsArray.find(s => s.id === specId);
if (spec) {
const docId = getDocIdFromInfoFile(spec.outputDir);
@@ -597,6 +619,20 @@ function updateOpenApiIndex() {
});
});
+ // Add uncategorized APIs to a catch-all category
+ const uncategorizedSpecs = openApiSpecsArray.filter(spec => !categorizedSpecs.has(spec.id));
+ if (uncategorizedSpecs.length > 0) {
+ console.warn(`β οΈ Found ${uncategorizedSpecs.length} uncategorized API(s): ${uncategorizedSpecs.map(s => s.id).join(', ')}`);
+ serviceLinksMarkdown += `\n## Other APIs\n\n`;
+ uncategorizedSpecs.forEach(spec => {
+ const docId = getDocIdFromInfoFile(spec.outputDir);
+ if (docId) {
+ const description = SERVICE_DESCRIPTIONS[spec.id] || 'API documentation';
+ serviceLinksMarkdown += `- **[${spec.id}](/${docId})** - ${description}\n`;
+ }
+ });
+ }
+
const indexContent = `---
title: OpenAPI Clients
sidebar_position: 7
From 8f76dae9da0232e1d0550045b3b8e14571c53990 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Sat, 14 Feb 2026 00:40:40 -0500
Subject: [PATCH 17/20] refactor: remove premature index generation from
preprocessing
The preprocessing script now only processes OpenAPI specs. Index generation
is deferred to the update-openapi-index script which runs AFTER docs are
generated, eliminating spurious warnings about missing .info.mdx files.
Co-Authored-By: Claude Sonnet 4.5
---
src/openapi/preprocessing.ts | 91 ------------------------------------
1 file changed, 91 deletions(-)
diff --git a/src/openapi/preprocessing.ts b/src/openapi/preprocessing.ts
index 32984cf3..e34d72b8 100644
--- a/src/openapi/preprocessing.ts
+++ b/src/openapi/preprocessing.ts
@@ -444,97 +444,6 @@ async function preprocessOpenApiSpecs() {
delete spec.specPathModified;
}
- // Create the index page for OpenAPI documentation with auto-generated service links
-
- // Helper function to find and read the document ID from a generated .info.mdx file
- function getDocIdFromInfoFile(outputDir: string): string | null {
- try {
- // Find .info.mdx files in the output directory
- const files = fs.readdirSync(outputDir);
- const infoFile = files.find(f => f.endsWith('.info.mdx'));
-
- if (infoFile) {
- const infoPath = path.join(outputDir, infoFile);
- const fileContent = fs.readFileSync(infoPath, 'utf8');
- const parsed = matter(fileContent);
-
- if (parsed.data.id) {
- // Return the full document path
- const relativePath = path.relative(OUTPUT_PREFIX, outputDir);
- return `OpenAPI-clients/${relativePath}/${parsed.data.id}`;
- }
- }
- } catch (error) {
- console.warn(`β οΈ Could not read info file from ${outputDir}: ${error}`);
- }
- return null;
- }
-
- // Build service links dynamically from openApiSpecsArray
- // Track which specs are categorized to find uncategorized ones
- const categorizedSpecs = new Set();
- let serviceLinksMarkdown = '';
-
- Object.entries(CATEGORY_MAPPING).forEach(([category, specIds]) => {
- serviceLinksMarkdown += `\n## ${category}\n\n`;
- specIds.forEach(specId => {
- categorizedSpecs.add(specId);
- const spec = openApiSpecsArray.find(s => s.id === specId);
- if (spec) {
- // Try to read the document ID from the generated .info.mdx file
- const docId = getDocIdFromInfoFile(spec.outputDir);
- if (docId) {
- const description = SERVICE_DESCRIPTIONS[specId] || 'API documentation';
- serviceLinksMarkdown += `- **[${spec.id}](/${docId})** - ${description}\n`;
- } else {
- console.warn(`β οΈ Could not generate link for ${spec.id} - .info.mdx file not found yet`);
- }
- }
- });
- });
-
- // Add uncategorized APIs to a catch-all category
- const uncategorizedSpecs = openApiSpecsArray.filter(spec => !categorizedSpecs.has(spec.id));
- if (uncategorizedSpecs.length > 0) {
- console.warn(`β οΈ Found ${uncategorizedSpecs.length} uncategorized API(s): ${uncategorizedSpecs.map(s => s.id).join(', ')}`);
- serviceLinksMarkdown += `\n## Other APIs\n\n`;
- uncategorizedSpecs.forEach(spec => {
- const docId = getDocIdFromInfoFile(spec.outputDir);
- if (docId) {
- const description = SERVICE_DESCRIPTIONS[spec.id] || 'API documentation';
- serviceLinksMarkdown += `- **[${spec.id}](/${docId})** - ${description}\n`;
- }
- });
- }
-
- const indexContent = `---
-title: OpenAPI Clients
-sidebar_position: 7
----
-# OpenAPI Clients
-
-Interactive API documentation for OpenTDF Platform services. Each endpoint includes request/response examples, parameter descriptions, and the ability to try requests directly in your browser.
-
-${serviceLinksMarkdown}
-
-## Getting Started
-
-1. Select a service from the list above or navigation sidebar
-2. Browse available endpoints and operations
-3. Review request parameters and response schemas
-4. Test endpoints using the "Try it" feature
-
-## Authentication
-
-Most endpoints require authentication. Configure your access token in the API documentation interface before testing endpoints.
-`
-
- // Ensure the file 'OPENAPI_INDEX_PAGE' exists
- fs.mkdirSync(path.dirname(OPENAPI_INDEX_PAGE), { recursive: true });
-
- fs.writeFileSync(OPENAPI_INDEX_PAGE, indexContent, 'utf8');
- console.log(`β
Created OpenAPI index page at ${OPENAPI_INDEX_PAGE}`);
-
console.log('β¨ OpenAPI preprocessing complete');
};
From 5138c032eb1edbc272475f0cb95681075e42dce8 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Tue, 17 Feb 2026 20:46:30 -0500
Subject: [PATCH 18/20] fix: correct OpenAPI index links to use directory paths
Fix broken links in the OpenAPI clients index page by removing
duplicate doc IDs from paths. Since generated API docs use index.mdx
files, links should point to the directory path rather than
directory/docId.
This fixes the build error where all OpenAPI client links were
incorrectly formatted as /OpenAPI-clients// instead
of /OpenAPI-clients/.
Co-Authored-By: Claude Sonnet 4.5
---
src/openapi/preprocessing.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/openapi/preprocessing.ts b/src/openapi/preprocessing.ts
index e34d72b8..d886855f 100644
--- a/src/openapi/preprocessing.ts
+++ b/src/openapi/preprocessing.ts
@@ -499,7 +499,7 @@ function updateOpenApiIndex() {
if (parsed.data.id) {
const relativePath = path.relative(OUTPUT_PREFIX, outputDir);
- return `OpenAPI-clients/${relativePath}/${parsed.data.id}`;
+ return `OpenAPI-clients/${relativePath}`;
}
}
} catch (error) {
From dc0a087f1671452dc355e66e3fc734841bced327 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Wed, 18 Feb 2026 09:25:55 -0500
Subject: [PATCH 19/20] fix: address code review feedback on homepage
- Fix invalid HTML nesting: move out of in Hero 2 section
- Replace inline styles on CTA section with marketing.css classes
- Add hero-list and marketing-cta CSS classes to marketing.css
Co-Authored-By: Claude Sonnet 4.6
---
src/css/marketing.css | 37 +++++++++++++++++++++++++++++++++++++
src/pages/index.tsx | 20 +++++++++++---------
2 files changed, 48 insertions(+), 9 deletions(-)
diff --git a/src/css/marketing.css b/src/css/marketing.css
index ad90eb17..78ba9ddc 100644
--- a/src/css/marketing.css
+++ b/src/css/marketing.css
@@ -209,6 +209,43 @@
}
}
+/* Hero list */
+.hero-list {
+ margin: 0.5rem 0 1rem 1.5rem;
+ color: inherit;
+ opacity: 0.9;
+}
+
+.hero-list li {
+ margin-bottom: 0.4rem;
+}
+
+/* Final CTA section */
+.marketing-cta {
+ padding: 4rem 0;
+ text-align: center;
+ background: #f8f9fa;
+}
+
+.marketing-cta__title {
+ font-size: 2.5rem;
+ margin-bottom: 1rem;
+ color: var(--ifm-color-primary);
+}
+
+.marketing-cta__subtitle {
+ font-size: 1.2rem;
+ margin-bottom: 2rem;
+ opacity: 0.8;
+}
+
+.marketing-cta__actions {
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
/* Visual enhancements */
.hero-icon-container {
position: relative;
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index e1861f9d..63a3260a 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -59,11 +59,13 @@ export default function Home() {
OpenTDF inverts this model. Policies travel with the data itself, so you can:
-
- - Revoke access after sharing β even after data has left your environment
- - Enforce controls in zero-trust environments β no VPN, no network dependency
- - Maintain a complete audit trail β know who accessed what, when, and where
-
+
+
+ - Revoke access after sharing β even after data has left your environment
+ - Enforce controls in zero-trust environments β no VPN, no network dependency
+ - Maintain a complete audit trail β know who accessed what, when, and where
+
+
This is data-centric security: protection that's embedded, not bolted on.
@@ -207,15 +209,15 @@ export default function Home() {
{/* Final CTA Section */}
-
+
-
+
Ready to Protect Your Data?
-
+
Choose your path and start building with OpenTDF today.
-
+
Start Tutorial
From b6a2f677f916217f92237b283ae7499b531dedc6 Mon Sep 17 00:00:00 2001
From: jp-ayyappan
Date: Wed, 18 Feb 2026 10:15:27 -0500
Subject: [PATCH 20/20] docs: sync README with docs/update-license branch
Add Documentation Structure section, Style Guide reference,
Testing with Feature Branches section, and Surge preview
deployment instructions to match the license PR.
Co-Authored-By: Claude Sonnet 4.6
---
README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 8627ebb5..f23ac996 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,15 @@ OpenTDF is an open source system for implementing data-centric security that ena
- **Policy Travels with Data**: Security controls remain attached wherever data goes
- **Trust Data Format (TDF)**: Open standard for self-protecting data
+## Documentation Structure
+
+Our documentation follows a user-needs approach with four main categories:
+
+- **π Tutorials**: Step-by-step learning experiences for hands-on practice
+- **π How-To Guides**: Problem-solving recipes for specific tasks and integrations
+- **π‘ Explanations**: Conceptual guides covering the "why" behind OpenTDF's design
+- **π Reference**: Technical specifications, API docs, and lookup information
+
## Contributing
We welcome contributions to improve our documentation! Please see our [Contributing Guide](CONTRIBUTING.md) for guidelines on:
@@ -24,6 +33,8 @@ We welcome contributions to improve our documentation! Please see our [Contribut
- Review and approval process
- Technical setup for contributors
+For style guidelines, please refer to our [Style Guide](STYLE_GUIDE.md).
+
## Quick Links
- **Live Documentation**: [docs.opentdf.io](https://docs.opentdf.io)
@@ -115,6 +126,41 @@ This command starts a local development server and opens up a browser window. Mo
This command generates static content into the `build` directory and can be served using any static contents hosting service.
+### Testing with Feature Branches
+
+The documentation site pulls content from multiple upstream repositories using Docusaurus remote content plugins. By default, content is fetched from the `main` branch of each repository. You can override this behavior using environment variables to test documentation changes from feature branches before they're merged.
+
+**Available Environment Variables:**
+
+- `PLATFORM_BRANCH` - Controls which branch to fetch from `opentdf/platform` (default: `main`)
+- `SPEC_BRANCH` - Controls which branch to fetch from `opentdf/spec` (default: `main`)
+- `OTDFCTL_BRANCH` - Controls which branch to fetch from `opentdf/otdfctl` (default: `main`)
+
+**Examples:**
+
+Test with all feature branches:
+```bash
+PLATFORM_BRANCH=my-platform-feature SPEC_BRANCH=my-spec-feature OTDFCTL_BRANCH=my-cli-feature npm run build
+```
+
+Test with a single feature branch:
+```bash
+SPEC_BRANCH=feature-branch-name npm run build
+```
+
+Test in development mode with feature branches:
+```bash
+PLATFORM_BRANCH=my-feature npm run start
+```
+
+**Use Cases:**
+
+- **Before merging PRs**: Test how documentation changes from upstream repos will look when integrated
+- **Cross-repo changes**: When making coordinated changes across multiple repositories, test the full integration locally
+- **Debugging**: Investigate issues with specific branches without affecting your local main branch
+
+**Note**: The branches must exist in the respective GitHub repositories and be accessible (public or you have access).
+
### Preview Deployment
Deploy to a Surge preview domain for testing changes before merging to production. **A free Surge account is required** - you'll be prompted to sign up the first time you deploy.
@@ -155,12 +201,10 @@ This documentation is licensed under the [Creative Commons Attribution 4.0 Inter
**Effective Date: February 13, 2026**
This project's documentation license has changed from:
-
- **Previous:** Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
- **New:** Creative Commons Attribution 4.0 International (CC BY 4.0)
**What this means:**
-
- β
You can use, adapt, and share this documentation under any terms
- β
You only need to provide attribution to the original work
- β
No longer required to share derivative works under the same license (ShareAlike requirement removed)