From 4dcfcf33d157b2311cdc98c2c002fb1a68966b92 Mon Sep 17 00:00:00 2001 From: Cory O'Daniel Date: Thu, 8 Jan 2026 16:34:58 -0800 Subject: [PATCH 1/4] Update docs w/o data,specs restriction --- docs/concepts/02-artifact-definitions.md | 28 +-- docs/concepts/03-artifacts.md | 247 +++++++++------------- docs/guides/custom_artifact_definition.md | 209 ++++++++---------- docs/guides/import-artifact.md | 76 +++---- 4 files changed, 230 insertions(+), 330 deletions(-) diff --git a/docs/concepts/02-artifact-definitions.md b/docs/concepts/02-artifact-definitions.md index cd7c51e..e299f0c 100644 --- a/docs/concepts/02-artifact-definitions.md +++ b/docs/concepts/02-artifact-definitions.md @@ -30,37 +30,36 @@ Artifact definitions are used to: ## Structure -Every artifact definition must contain two top-level fields: - -1. `data` (object): Contains data that will be encrypted-at-rest and is generally consider 'secret.' -2. `specs` (object): Contains specs about the artifact that was provisioned or imported, and can be searched and displayed in the UI. +Artifact definitions use JSON Schema to define the structure and validation rules for artifacts. You have complete flexibility in defining your schema structure to match your organization's needs. ### Example Structure -All artifact definitions must include top-level `data` and `specs` fields. You can define your own structure using JSON Schema. - ```json { "$schema": "http://json-schema.org/draft-07/schema", "type": "object", - "required": ["data", "specs"], "properties": { - "data": { + "authentication": { "type": "object", "properties": { - // Data properties here + "hostname": { "type": "string" }, + "port": { "type": "integer" }, + "username": { "type": "string" } } }, - "specs": { + "infrastructure": { "type": "object", "properties": { - // Spec properties here + "arn": { "type": "string" }, + "region": { "type": "string" } } } } } ``` +You can mark sensitive fields using the `$md.sensitive` annotation to mask them in GET operations. See the [Massdriver Annotations](/json-schema-cheat-sheet/massdriver-annotations) documentation for details. + ## Artifact Lifecycle and Connection Phases The lifecycle of artifact connections spans from initial package linking to final data injection. Through distinct phases of type validation and data exchange, artifact definitions ensure type safety and data integrity across your deployment pipeline. @@ -120,10 +119,11 @@ https://api.massdriver.cloud/artifact-definitions/ORG/NAME ## Best Practices -1. Always include both `data` and `specs` fields -2. Use clear, descriptive names for artifact types -3. Include proper validation rules in the schema +1. Use clear, descriptive names for artifact types +2. Include proper validation rules in the schema +3. Use `$md.sensitive` to protect sensitive fields 4. Document any special requirements or constraints +5. Structure your schema to match your infrastructure abstractions For a complete guide to creating artifact definitions, see [Creating Artifact Definitions](/guides/custom-artifact-definition). diff --git a/docs/concepts/03-artifacts.md b/docs/concepts/03-artifacts.md index 6c4bd20..f897aed 100644 --- a/docs/concepts/03-artifacts.md +++ b/docs/concepts/03-artifacts.md @@ -19,75 +19,42 @@ Instead of manually copying connection strings, credentials, and resource identi ## Artifact Structure -Every artifact contains two top-level fields that serve distinct purposes. The specific contents of `data` and `specs` are defined by the [artifact definition](/concepts/artifact-definitions) that the artifact conforms to. You decide what `data` comprises your abstraction (e.g., what makes up "postgresql" for your organization) and what `specs` about that resource you want available in the platform. +Think of an [artifact definition](/concepts/artifact-definitions) as a class in object-oriented programming—it defines the schema and validation rules. An artifact is like an instance of that class—it's the actual data about a specific piece of infrastructure you've provisioned. -### `data` - Secure, Encrypted Information +Each artifact definition describes what data its artifacts will contain. For example: -**Type**: `object` (encrypted at rest) -**Purpose**: Contains sensitive information about the provisioned resource +- A **PostgreSQL artifact** might include connection credentials, IAM policies, database metadata, and secret manager IDs to access credentials +- A **Kubernetes cluster artifact** might include kubeconfig data, API endpoints, and cluster version info +- An **S3 bucket artifact** might include bucket ARNs, IAM policies to access it, and region information -The `data` field stores encrypted, sensitive information that is only accessible to authorized packages. This typically includes: +You decide what goes in your artifacts based on what downstream bundles need to connect and interact with that infrastructure. -- **Connection credentials**: Database passwords, API keys, authentication tokens -- **Cloud resource identifiers**: Resource ARNs, IDs, endpoints -- **IAM configuration**: Policy documents, role ARNs, service account configurations -- **Network configuration**: Private endpoints, security group IDs, VPC information - -**Example**: +**Example PostgreSQL Artifact**: ```json { - "data": { - "authentication": { - "hostname": "db.example.com", - "port": 5432, - "username": "app_user", - "password": "encrypted_secret_value", - "ssl": true - }, - "iam": { - "role_arn": "arn:aws:iam::123456789012:role/db-access-role", - "policy": "{...}" - } + "authentication": { + "hostname": "db.example.com", + "port": 5432, + "username": "app_user", + "password": "secret_value", + "ssl": true + }, + "infrastructure": { + "arn": "arn:aws:rds:us-west-2:123456789012:db:mydb", + "region": "us-west-2" + }, + "iam": { + "role_arn": "arn:aws:iam::123456789012:role/db-access-role", + "policy": "{...}" } } ``` -The `data` field is encrypted at rest using row-level encryption and is never displayed in the UI or exposed in logs. Only packages that have a valid connection to the artifact can access its data. - -### `specs` - Public, Searchable Metadata - -**Type**: `object` -**Purpose**: Contains non-sensitive metadata for filtering, searching, and display +### Sensitive Data Protection -The `specs` field stores public metadata that can be safely displayed in the UI and used for filtering and searching artifacts. This typically includes: - -- **Cloud provider information**: Region, availability zone, account ID -- **Resource characteristics**: Instance size, storage type, feature flags -- **Tags and labels**: Environment tags, cost allocation tags, organizational metadata -- **Status information**: Resource state, health indicators - -**Example**: -```json -{ - "specs": { - "aws": { - "region": "us-west-2", - "account_id": "123456789012" - }, - "database": { - "engine": "postgresql", - "version": "15.2", - "instance_class": "db.t3.medium" - }, - "tags": { - "Environment": "production", - "Team": "platform" - } - } -} -``` +You can mark specific fields as sensitive in your artifact definition using `$md.sensitive: true`. These fields will be automatically masked as `[SENSITIVE]` when you view artifacts in the UI or query them via the API. When you actually need the real values (like when deploying a bundle that connects to that database), use the `downloadArtifact` operation. All artifact data is encrypted at rest and in transit. -The `specs` field is visible in the Massdriver UI, allowing users to search and filter artifacts by region, tags, or other metadata without exposing sensitive connection details. +See [Massdriver Annotations](/json-schema-cheat-sheet/massdriver-annotations) for details on sensitive field masking. ## Artifact Origins @@ -267,9 +234,9 @@ Artifacts enforce proper dependency ordering: Artifacts must conform to an [artifact definition](/concepts/artifact-definitions), which is a JSON Schema that defines: -- The structure of the `data` field -- The structure of the `specs` field +- The structure and properties of the artifact - Validation rules and constraints +- Sensitive field annotations - UI display configuration Artifact definitions ensure that: @@ -281,23 +248,23 @@ See [Artifact Definitions](/concepts/artifact-definitions) for detailed informat ## Best Practices -### Data vs Specs Separation +### Sensitive Data Management -**Keep sensitive data in `data`**: +**Use `$md.sensitive` for sensitive fields**: - Credentials, passwords, API keys - Private endpoints and connection strings -- IAM policies and role ARNs -- Any information that should be encrypted - -**Keep public metadata in `specs`**: -- Region, availability zone, account information -- Resource characteristics (size, type, version) -- Tags and organizational metadata -- Status and health information - -This separation enables: -- Secure storage of sensitive information -- UI display and filtering without exposing secrets +- IAM policies and tokens +- Any information that should be masked + +**Organize your artifact structure**: +- Group related properties logically (e.g., `authentication`, `infrastructure`, `iam`) +- Use clear, descriptive field names +- Include metadata useful for filtering and searching +- Document expected values and formats + +This approach enables: +- Secure storage with automatic field masking +- Flexible schema design matching your needs - Compliance with security best practices ### Artifact Naming @@ -339,34 +306,30 @@ A PostgreSQL bundle produces an artifact with connection details: ```json { - "data": { - "authentication": { - "hostname": "prod-db.region.rds.amazonaws.com", - "port": 5432, - "username": "app_user", - "password": "encrypted_password", - "database": "myapp_prod", - "ssl": true - }, - "iam": { - "role_arn": "arn:aws:iam::123456789012:role/rds-access", - "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[...]}" - } + "authentication": { + "hostname": "prod-db.region.rds.amazonaws.com", + "port": 5432, + "username": "app_user", + "password": "secret_password", + "database": "myapp_prod", + "ssl": true + }, + "iam": { + "role_arn": "arn:aws:iam::123456789012:role/rds-access", + "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[...]}" + }, + "aws": { + "region": "us-west-2", + "account_id": "123456789012" + }, + "database": { + "engine": "postgresql", + "version": "15.2", + "instance_class": "db.r6g.xlarge" }, - "specs": { - "aws": { - "region": "us-west-2", - "account_id": "123456789012" - }, - "database": { - "engine": "postgresql", - "version": "15.2", - "instance_class": "db.r6g.xlarge" - }, - "tags": { - "Environment": "production", - "Team": "platform" - } + "tags": { + "Environment": "production", + "Team": "platform" } } ``` @@ -377,30 +340,26 @@ A Kubernetes cluster bundle produces an artifact with cluster connection details ```json { - "data": { - "authentication": { - "kubeconfig": "encrypted_kubeconfig_content", - "server": "https://cluster.example.com", - "certificate_authority_data": "encrypted_ca_data" - }, - "service_account": { - "name": "massdriver-sa", - "namespace": "default", - "token": "encrypted_token" - } + "authentication": { + "kubeconfig": "kubeconfig_content", + "server": "https://cluster.example.com", + "certificate_authority_data": "ca_data" }, - "specs": { - "kubernetes": { - "version": "1.28", - "provider": "eks" - }, - "aws": { - "region": "us-west-2" - }, - "cluster": { - "node_count": 3, - "node_instance_type": "m5.large" - } + "service_account": { + "name": "massdriver-sa", + "namespace": "default", + "token": "secret_token" + }, + "kubernetes": { + "version": "1.28", + "provider": "eks" + }, + "aws": { + "region": "us-west-2" + }, + "cluster": { + "node_count": 3, + "node_instance_type": "m5.large" } } ``` @@ -411,31 +370,25 @@ An S3 bucket bundle produces an artifact with bucket details: ```json { - "data": { - "bucket": { - "name": "my-app-logs-prod", - "arn": "arn:aws:s3:::my-app-logs-prod", - "region": "us-west-2" - }, - "iam": { - "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[...]}", - "role_arn": "arn:aws:iam::123456789012:role/s3-access" - } + "bucket": { + "name": "my-app-logs-prod", + "arn": "arn:aws:s3:::my-app-logs-prod", + "region": "us-west-2", + "versioning": true, + "encryption": "AES256", + "lifecycle_rules": true + }, + "iam": { + "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[...]}", + "role_arn": "arn:aws:iam::123456789012:role/s3-access" + }, + "aws": { + "region": "us-west-2", + "account_id": "123456789012" }, - "specs": { - "aws": { - "region": "us-west-2", - "account_id": "123456789012" - }, - "bucket": { - "versioning": true, - "encryption": "AES256", - "lifecycle_rules": true - }, - "tags": { - "Purpose": "application-logs", - "Environment": "production" - } + "tags": { + "Purpose": "application-logs", + "Environment": "production" } } ``` diff --git a/docs/guides/custom_artifact_definition.md b/docs/guides/custom_artifact_definition.md index 8cc48d5..c3c74a4 100644 --- a/docs/guides/custom_artifact_definition.md +++ b/docs/guides/custom_artifact_definition.md @@ -39,18 +39,14 @@ With the [Massdriver CLI](../cli/00-overview.md), you've got the toolkit you nee "title": "Artifact Definition Name", "description": "", "additionalProperties": false, - "required": [ - "data", - "specs" - ], "properties": { - "data": { - "title": "Artifact Data", + "authentication": { + "title": "Authentication", "type": "object", "properties": {} }, - "specs": { - "title": "Artifact Specs", + "infrastructure": { + "title": "Infrastructure", "type": "object", "properties": {} } @@ -62,15 +58,13 @@ With the [Massdriver CLI](../cli/00-overview.md), you've got the toolkit you nee ### Step 3: Key Components of an Artifact Definition -Every custom artifact definition should include: - -- **Data Block**: This is where you stash the sensitive details (passwords, connection strings, you name it). -- **Specs Block**: Here's where the non-sensitive details go, like API versions and cloud regions. +Structure your artifact definition to match your infrastructure abstraction. Group related properties logically and use `$md.sensitive: true` to protect sensitive fields like passwords and tokens. ### Step 4: Tailoring Your Definition -1. **Refine the Data and Specs Blocks**: Adapt these sections to match your specific artifact needs. -2. **Prune What You Don't Need**: If the copied definition includes irrelevant bits (like RBAC settings you're not using), cut them out or alter them. +1. **Define Your Structure**: Add properties that match your infrastructure needs. +2. **Mark Sensitive Fields**: Use `$md.sensitive: true` for passwords, tokens, and other secrets. +3. **Prune What You Don't Need**: If the copied definition includes irrelevant bits, cut them out or alter them. By the end of this step, your definition should look something like this: ```json @@ -84,115 +78,92 @@ By the end of this step, your definition should look something like this: "description": "", "additionalProperties": false, "required": [ - "data", - "specs" + "infrastructure", + "authentication" ], "properties": { - "data": { - "title": "Artifact Data", + "infrastructure": { + "title": "Infrastructure configuration", "type": "object", "required": [ - "infrastructure", - "authentication", - "security" + "foo", + "bar" ], "properties": { - "infrastructure": { - "title": "Infrastructure configuration", - "type": "object", - "required": [ - "foo", - "bar" - ], - "properties": { - "foo": { - "type": "string", - "title": "Foo", - "description": "Foo description", - "examples": [ - ], - "pattern": "^.*+$", - "message": { - "pattern": "Must be a valid format for foo." - } - }, - "bar": { - "title": "Bar", - "description": "Bar description", - "additionalProperties": false, - "examples": [ - ], - "type": "string" - } + "foo": { + "type": "string", + "title": "Foo", + "description": "Foo description", + "examples": [], + "pattern": "^.*+$", + "message": { + "pattern": "Must be a valid format for foo." } }, - "authentication": { - "title": "Authentication configuration", + "bar": { + "title": "Bar", + "description": "Bar description", + "additionalProperties": false, + "examples": [], + "type": "string" + } + } + }, + "authentication": { + "title": "Authentication configuration", + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "title": "Token", + "type": "string", + "$md": { + "sensitive": true + } + } + } + }, + "iam": { + "title": "IAM", + "description": "IAM Roles And Scopes", + "additionalProperties": false, + "patternProperties": { + "^[a-z]+[a-z_]*[a-z]$": { "type": "object", "required": [ - "foobar" + "role", + "scope" ], "properties": { - "foobar": { - "title": "Foobar", + "role": { + "title": "Role", + "description": "Cloud Role", + "pattern": "^[a-zA-Z ]+$", + "message": { + "pattern": "Must be a valid Cloud Role (uppercase, lowercase letters and spaces)" + }, + "examples": [ + "Data Reader" + ] + }, + "scope": { + "title": "Scope", + "description": "Cloud IAM Scope (cloud resource identifier)", "type": "string" } } - }, - "security": { - "title": "Security", - "description": "Security Configuration", - "additionalProperties": false, - "required": [], - "properties": { - "iam": { - "title": "IAM", - "description": "IAM Roles And Scopes", - "additionalProperties": false, - "patternProperties": { - "^[a-z]+[a-z_]*[a-z]$": { - "type": "object", - "required": [ - "role", - "scope" - ], - "properties": { - "role": { - "title": "Role", - "description": "Cloud Role", - "pattern": "^[a-zA-Z ]+$", - "message": { - "pattern": "Must be a valid Cloud Role (uppercase, lowercase letters and spaces)" - }, - "examples": [ - "Data Reader" - ] - }, - "scope": { - "title": "Scope", - "description": "Cloud IAM Scope (cloud resource identifier)", - "type": "string" - } - } - } - } - } - } } } }, - "specs": { - "title": "Artifact Specs", + "cloud": { "type": "object", "properties": { - "cloud": { - "properties": { - "region": { - "type": "string", - "title": "Cloud Region", - "description": "Select the cloud region you'd like to provision your resources in." - } - } + "region": { + "type": "string", + "title": "Cloud Region", + "description": "Select the cloud region you'd like to provision your resources in." } } } @@ -228,28 +199,22 @@ resource "massdriver_artifact" "artifact_definition_name" { name = "Artifact Dummy Resource ${var.md_metadata.name_prefix}" artifact = jsonencode( { - data = { - infrastructure = { - foo = artifact_dummy_resource.main.foo - bar = artifact_dummy_resource.main.bar - } - authentication = { - foobar = artifact_dummy_resource.main.foobar - } - security = { - iam = { - "read" = { - role = "Data Reader" - scope = artifact_dummy_resource.main.id - } - } - } + infrastructure = { + foo = artifact_dummy_resource.main.foo + bar = artifact_dummy_resource.main.bar } - specs = { - cloud = { - region = artifact_dummy_resource.main.region + authentication = { + token = artifact_dummy_resource.main.token + } + iam = { + "read" = { + role = "Data Reader" + scope = artifact_dummy_resource.main.id } } + cloud = { + region = artifact_dummy_resource.main.region + } } ) } diff --git a/docs/guides/import-artifact.md b/docs/guides/import-artifact.md index ab6def0..8a1839d 100644 --- a/docs/guides/import-artifact.md +++ b/docs/guides/import-artifact.md @@ -22,48 +22,36 @@ We'll also need a custom artifact that meets that schema, populated with actual "title": "AWS VPC", "description": "My custom AWS VPC", "required": [ - "data" + "infrastructure" ], "properties": { - "data": { - "title": "Artifact Data", - "type": "object", + "infrastructure": { + "title": "Infrastructure configuration", "required": [ - "infrastructure" + "arn", + "cidr" ], + "type": "object", "properties": { - "infrastructure": { - "title": "Infrastructure configuration", - "required": [ - "arn", - "cidr", - ], - "type": "object", - "properties": { - "arn": { - "type": "string", - "title": "AWS ARN", - "description": "Amazon Resource Name", - } - "cidr": { - "type" : "string", - "title": "CIDR", - "description": "CIDR block for the VPC" - } - } + "arn": { + "type": "string", + "title": "AWS ARN", + "description": "Amazon Resource Name" + }, + "cidr": { + "type": "string", + "title": "CIDR", + "description": "CIDR block for the VPC" } } }, - "specs": { - "title": "Artifact Specs", + "aws": { "type": "object", "properties": { - "aws": { - "region": { - "type": "string", - "title": "Region", - "description": "AWS Region to provision in.", - } + "region": { + "type": "string", + "title": "Region", + "description": "AWS Region to provision in." } } } @@ -72,16 +60,12 @@ We'll also need a custom artifact that meets that schema, populated with actual ``` ```json title="artifact.json" { - "data": { - "infrastructure": { - "arn": "arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0", - "cidr": "10.0.0.0/16" - } + "infrastructure": { + "arn": "arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0", + "cidr": "10.0.0.0/16" }, - "specs": { - "aws": { - "region": "us-west-2" - } + "aws": { + "region": "us-west-2" } } ``` @@ -119,10 +103,9 @@ You can access our GraphiQL interface [here](https://api.massdriver.cloud/api/gr ```graphql title="createArtifact.gql" mutation importVpc($orgId: ID!) { createArtifact( - data: "{\"infrastructure\":{\"arn\":\"arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0\",\"cidr\":\"10.0.0.0/16\"}}" + payload: "{\"infrastructure\":{\"arn\":\"arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0\",\"cidr\":\"10.0.0.0/16\"},\"aws\":{\"region\":\"us-west-2\"}}" name: "my-artifact-name" organizationId: $orgId - specs: "{\"aws\":{\"region\":\"us-west-2\"}}" type: "mymdorg/myartifactdef" ){ result{id} @@ -153,10 +136,9 @@ function setItem() { return client.request(` { createArtifact( - data: "{\"infrastructure\":{\"arn\":\"arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0\",\"cidr\":\"10.0.0.0/16\"}}" + payload: "{\"infrastructure\":{\"arn\":\"arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0\",\"cidr\":\"10.0.0.0/16\"},\"aws\":{\"region\":\"us-west-2\"}}" name: "my-artifact-name" organizationId: $orgId - specs: "{\"aws\":{\"region\":\"us-west-2\"}}" type: "mymdorg/myartifactdef" ){ result{id} @@ -181,7 +163,7 @@ function setItem() { 'Content-Type': 'application/json', //'Authorization': 'Bearer YOUR_AUTH_TOKEN' }, - body: '{"query":"mutationimportVpc($orgId:ID!){createArtifact(data:\"{\\\"infrastructure\\\":{\\\"arn\\\":\\\"arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0\\\",\\\"cidr\\\":\\\"10.0.0.0/16\\\"}}\"name:\"my-artifact-name\"organizationId:$orgIdspecs:\"{\\\"aws\\\":{\\\"region\\\":\\\"us-west-2\\\"}}\"type:\"mymdorg/myartifactdef\"){result{id}messages{message}successful}}"}', + body: '{"query":"mutationimportVpc($orgId:ID!){createArtifact(payload:\"{\\\"infrastructure\\\":{\\\"arn\\\":\\\"arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0\\\",\\\"cidr\\\":\\\"10.0.0.0/16\\\"},\\\"aws\\\":{\\\"region\\\":\\\"us-west-2\\\"}}\"name:\"my-artifact-name\"organizationId:$orgIdtype:\"mymdorg/myartifactdef\"){result{id}messages{message}successful}}"}', }) } ``` @@ -192,6 +174,6 @@ function setItem() { ```bash title="cURL" curl 'https://api.massdriver.cloud/api/graphiql' -H 'Authorization: Bearer YOUR_AUTH_TOKEN' - -d '{"query":"mutationimportVpc($orgId:ID!){createArtifact(data:\"{\\\"infrastructure\\\":{\\\"arn\\\":\\\"arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0\\\",\\\"cidr\\\":\\\"10.0.0.0/16\\\"}}\"name:\"my-artifact-name\"organizationId:$orgIdspecs:\"{\\\"aws\\\":{\\\"region\\\":\\\"us-west-2\\\"}}\"type:\"mymdorg/myartifactdef\"){result{id}messages{message}successful}}"}' + -d '{"query":"mutationimportVpc($orgId:ID!){createArtifact(payload:\"{\\\"infrastructure\\\":{\\\"arn\\\":\\\"arn:aws:ec2:us-west-2:123456789012:vpc/vpc-1234567890abcdef0\\\",\\\"cidr\\\":\\\"10.0.0.0/16\\\"},\\\"aws\\\":{\\\"region\\\":\\\"us-west-2\\\"}}\"name:\"my-artifact-name\"organizationId:$orgIdtype:\"mymdorg/myartifactdef\"){result{id}messages{message}successful}}"}' ``` From f0d75cddae84804fbbe92804c6852dd7127499d2 Mon Sep 17 00:00:00 2001 From: Cory O'Daniel Date: Thu, 8 Jan 2026 16:42:15 -0800 Subject: [PATCH 2/4] terminology --- docs/concepts/02-artifact-definitions.md | 26 +++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/concepts/02-artifact-definitions.md b/docs/concepts/02-artifact-definitions.md index e299f0c..71e4915 100644 --- a/docs/concepts/02-artifact-definitions.md +++ b/docs/concepts/02-artifact-definitions.md @@ -34,17 +34,31 @@ Artifact definitions use JSON Schema to define the structure and validation rule ### Example Structure +Let's say you're defining a PostgreSQL database artifact. By creating a concrete schema for "what is a PostgreSQL database" in your organization, you enable: + +- **Automated Security & Credential Management**: Applications automatically receive the correct credentials—no secrets in code, no manual rotation, no credential leaks +- **Tool Interoperability**: A Terraform bundle provisions a database, a Helm chart consumes it—different tools, zero manual wiring +- **Prevent Misconfigurations**: Type-safe connections stop you from wiring a Redis client to a PostgreSQL database. Misconfigurations cause most production outages—artifact definitions prevent them at deploy time +- **Automated Operations**: Monitoring and runbooks auto-generate from artifact data—every database gets the right alerts without manual setup + +Here's what a PostgreSQL artifact definition might look like: + ```json { "$schema": "http://json-schema.org/draft-07/schema", "type": "object", + "title": "PostgreSQL Database", "properties": { "authentication": { "type": "object", "properties": { "hostname": { "type": "string" }, "port": { "type": "integer" }, - "username": { "type": "string" } + "username": { "type": "string" }, + "password": { + "type": "string", + "$md.sensitive": true + } } }, "infrastructure": { @@ -58,7 +72,9 @@ Artifact definitions use JSON Schema to define the structure and validation rule } ``` -You can mark sensitive fields using the `$md.sensitive` annotation to mask them in GET operations. See the [Massdriver Annotations](/json-schema-cheat-sheet/massdriver-annotations) documentation for details. +Any bundle that produces a PostgreSQL artifact must include all these fields. Any bundle that consumes a PostgreSQL artifact knows exactly what data it will receive. This contract eliminates manual configuration and enables true infrastructure automation. + +You can mark sensitive fields using `$md.sensitive` to automatically mask them in GET operations. See the [Massdriver Annotations](/json-schema-cheat-sheet/massdriver-annotations) documentation for details. ## Artifact Lifecycle and Connection Phases @@ -75,7 +91,7 @@ Once the upstream package completes provisioning and emits its artifact data, th ### Linking Process The connection lifecycle follows these steps: -1. When two manifests are linked on the canvas, the system validates that the artifact types are compatible +1. When two bundles are linked on the canvas, the system validates that the artifact types are compatible 2. The connection is established when the source artifact's type matches the destination's expected type 3. The system ensures no cyclical links are created 4. Each destination field can only have one active link at a time @@ -84,8 +100,8 @@ The connection lifecycle follows these steps: Artifact definitions are referenced in massdriver.yaml files under two main sections: -1. `:artifacts`: Defines the artifacts that a bundle can produce -2. `:connections`: Defines the artifacts that a bundle can consume +1. `artifacts`: Defines the artifacts that a bundle can produce +2. `connections`: Defines the artifacts that a bundle can consume An example `massdriver.yaml` file for an RDS OpenTofu Module: ```yaml From 3b4428281e02963bc4bded3f2cd372af2c92b990 Mon Sep 17 00:00:00 2001 From: Cory O'Daniel Date: Thu, 8 Jan 2026 16:47:26 -0800 Subject: [PATCH 3/4] clarifications --- docs/concepts/03-artifacts.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/concepts/03-artifacts.md b/docs/concepts/03-artifacts.md index f897aed..20d16fd 100644 --- a/docs/concepts/03-artifacts.md +++ b/docs/concepts/03-artifacts.md @@ -23,7 +23,7 @@ Think of an [artifact definition](/concepts/artifact-definitions) as a class in Each artifact definition describes what data its artifacts will contain. For example: -- A **PostgreSQL artifact** might include connection credentials, IAM policies, database metadata, and secret manager IDs to access credentials +- A **PostgreSQL artifact** might include connection credentials, IAM policies, database metadata, and secret manager references - A **Kubernetes cluster artifact** might include kubeconfig data, API endpoints, and cluster version info - An **S3 bucket artifact** might include bucket ARNs, IAM policies to access it, and region information @@ -69,7 +69,7 @@ Provisioned artifacts are the most common type. They are automatically created w **Characteristics**: - Created by deployments during the provisioning process - Associated with a specific [package](/concepts/packages) and bundle field -- Identified by `package.name_prefix-field` (e.g., `api-prod-database-1234-instance`) +- Identified by package slug (project-environment-manifest) + field name - Automatically updated when the package is redeployed - Can only be updated or deleted by deployments - Lifecycle is tied to the package that created them @@ -155,25 +155,25 @@ Artifacts are identified differently based on their origin: ### Provisioned Artifacts -Identified by: `package.name_prefix-field` +Identified by: `{project-slug}-{environment-slug}-{manifest-slug}-{artifact_field}` -**Format**: `{package_name_prefix}-{artifact_field}` - -The package name prefix follows the format `{project-slug}-{environment-slug}-{manifest-slug}-{suffix}`. Note that individual slugs (project, environment, manifest) cannot contain hyphens—hyphens are only used to separate the slug components. +Combines the project, environment, and manifest slugs with the artifact field name. **Example**: -- Package name prefix: `api-prod-database-1234` (project: `api`, environment: `prod`, manifest: `database`, suffix: `1234`) +- Project: `api` +- Environment: `prod` +- Manifest: `database` - Artifact field: `instance` -- Artifact identifier: `api-prod-database-1234-instance` +- **Artifact identifier**: `api-prod-database-instance` **Another example**: -- Package name prefix: `api-prod-database-1234` -- Artifact field: `authentication` (if the bundle output field was named `authentication`) -- Artifact identifier: `api-prod-database-1234-authentication` +- Project: `api`, Environment: `prod`, Manifest: `database` +- Artifact field: `authentication` +- **Artifact identifier**: `api-prod-database-authentication` This format provides: - Human-readable, meaningful identifiers -- Consistency across related artifacts +- Stable identifiers across package redeployments - Support for IaC tools that don't maintain state - Clear association with the source package @@ -272,7 +272,7 @@ This approach enables: **For Provisioned Artifacts**: - Use descriptive field names in your bundle's `artifacts` section - The artifact name should clearly indicate what resource it represents -- Consider the package name prefix when choosing field names +- Remember the field name becomes part of the artifact identifier (e.g., `api-prod-database-instance`) **For Imported Artifacts**: - Use clear, descriptive names that indicate the artifact's purpose From 82c9644d13d2cec3d182c320c41c3e6988aa8040 Mon Sep 17 00:00:00 2001 From: Cory O'Daniel Date: Thu, 8 Jan 2026 16:49:49 -0800 Subject: [PATCH 4/4] clarifications --- docs/concepts/03-artifacts.md | 2 +- docs/guides/custom_artifact_definition.md | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/concepts/03-artifacts.md b/docs/concepts/03-artifacts.md index 20d16fd..0f197fa 100644 --- a/docs/concepts/03-artifacts.md +++ b/docs/concepts/03-artifacts.md @@ -157,7 +157,7 @@ Artifacts are identified differently based on their origin: Identified by: `{project-slug}-{environment-slug}-{manifest-slug}-{artifact_field}` -Combines the project, environment, and manifest slugs with the artifact field name. +This format creates human-friendly, unique identifiers for your infrastructure artifacts. Instead of remembering UUIDs, you get meaningful names like `api-prod-database-instance` that tell you exactly what resource you're looking at and where it lives. **Example**: - Project: `api` diff --git a/docs/guides/custom_artifact_definition.md b/docs/guides/custom_artifact_definition.md index c3c74a4..415639e 100644 --- a/docs/guides/custom_artifact_definition.md +++ b/docs/guides/custom_artifact_definition.md @@ -183,13 +183,19 @@ Once published, snag your artifact definition with the `mass definition get org/ Now that your custom artifact definition is published, you can use it in your bundles. Just reference it in your bundle's `artifacts` field and structure your `_artifacts.tf` file, and you're good to go. +:::tip Recommended: Omit Organization Prefix +When referencing artifact definitions from your own organization, you can omit the organization prefix. Massdriver will automatically use your organization's definitions. This keeps your bundle configuration cleaner and more portable. +::: + ``` yaml massdriver.yaml artifacts: required: - artifact_definition_name properties: artifact_definition_name: - $ref: acme/artifact-definition-name + # Recommended: omit org prefix for your own artifact definitions + $ref: artifact-definition-name + # Also valid: acme/artifact-definition-name ``` ``` hcl src/_artifacts.tf