├── CODEOWNERS ├── docs ├── images │ ├── README.md │ ├── Slack_Mark-24x24.png │ ├── so-image-24x24.png │ ├── gitter-icon-24x24.png │ └── Twitter_Social_Icon_24x24.png ├── specs │ ├── parallel-lifecycle-script-execution.md │ ├── features-user-env-variables.md │ ├── gpu-host-requirement.md │ ├── secrets-support.md │ ├── declarative-secrets.md │ ├── devcontainer-lockfile.md │ ├── devcontainer-id-variable.md │ ├── features-contribute-lifecycle-scripts.md │ ├── image-metadata.md │ ├── features-legacyIds-deprecated-properties.md │ ├── devcontainer-templates-distribution.md │ ├── supporting-tools.md │ ├── devcontainer-templates.md │ ├── devcontainer-features-distribution.md │ ├── feature-dependencies.md │ └── devcontainer-reference.md └── README.md ├── images └── dev-container-stages.png ├── CODE_OF_CONDUCT.md ├── schemas ├── devContainer.schema.json ├── devContainerFeature.schema.json └── devContainer.base.schema.json ├── proposals ├── README.md ├── build-options.md └── features-library.md ├── LICENSE-CODE ├── SECURITY.md ├── README.md ├── CONTRIBUTING.md ├── .gitignore └── LICENSE /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @devcontainers/maintainers 2 | -------------------------------------------------------------------------------- /docs/images/README.md: -------------------------------------------------------------------------------- 1 | # Images 2 | 3 | These images are used in READMEs. 4 | -------------------------------------------------------------------------------- /docs/images/Slack_Mark-24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devcontainers/spec/HEAD/docs/images/Slack_Mark-24x24.png -------------------------------------------------------------------------------- /docs/images/so-image-24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devcontainers/spec/HEAD/docs/images/so-image-24x24.png -------------------------------------------------------------------------------- /images/dev-container-stages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devcontainers/spec/HEAD/images/dev-container-stages.png -------------------------------------------------------------------------------- /docs/images/gitter-icon-24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devcontainers/spec/HEAD/docs/images/gitter-icon-24x24.png -------------------------------------------------------------------------------- /docs/images/Twitter_Social_Icon_24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devcontainers/spec/HEAD/docs/images/Twitter_Social_Icon_24x24.png -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /schemas/devContainer.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "allOf": [ 3 | { 4 | "$ref": "./devContainer.base.schema.json" 5 | }, 6 | { 7 | "$ref": "https://raw.githubusercontent.com/microsoft/vscode/main/extensions/configuration-editing/schemas/devContainer.codespaces.schema.json" 8 | }, 9 | { 10 | "$ref": "https://raw.githubusercontent.com/microsoft/vscode/main/extensions/configuration-editing/schemas/devContainer.vscode.schema.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /proposals/README.md: -------------------------------------------------------------------------------- 1 | # Proposals 2 | 3 | The files in this folder detail active proposals to the Dev Container Specification. 4 | 5 | We add any proposal to the [**proposals folder**](https://github.com/devcontainers/spec/tree/main/proposals), only if the proposal is accepted. It stays in that folder until the implementation is in progress. Once code/schema changes are released, we move it into the [**specs folder**](https://github.com/devcontainers/spec/tree/main/docs/specs). 6 | 7 | > **Note:** Our [contributing.md](/contributing.md) documents guidelines on contributing to the spec, as well as labels (proposal and finalization) defined for this process for GitHub issues. 8 | -------------------------------------------------------------------------------- /LICENSE-CODE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /docs/specs/parallel-lifecycle-script-execution.md: -------------------------------------------------------------------------------- 1 | # Parallel Lifecycle Script Execution 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/83 5 | * CLI PR: https://github.com/devcontainers/cli/pull/172 6 | 7 | Below is the original proposal. 8 | 9 | ## Goal 10 | 11 | Support executing multiple lifecycle scripts in parallel by providing them in `object` form. 12 | 13 | ## Motivation 14 | 15 | Dev containers support a single command for each of their lifecycle scripts. While serial execution of multiple commands can be achieved with `;`, `&&`, etc. parallel is less straightforward and so deserves first-class support. 16 | 17 | ## Spec changes 18 | 19 | All lifecycle scripts will be extended to support `object` types. The key of the `object` will be a unique name for the command and the value will be the `string` or `array` command. Each command must exit successfully for the stage to be considered successful. 20 | 21 | Each entry in the `object` will be run in parallel during that lifecycle step. 22 | 23 | ### Example 24 | 25 | ```json 26 | { 27 | "postCreateCommand": { 28 | "server": "npm start", 29 | "db": ["mysql", "-u", "root", "-p", "my database"] 30 | } 31 | } 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/specs/features-user-env-variables.md: -------------------------------------------------------------------------------- 1 | # User Env Variables for Features 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/91 5 | * CLI PR: https://github.com/devcontainers/cli/pull/228 6 | 7 | Below is the original proposal. 8 | 9 | ## Goal 10 | 11 | Feature scripts run as the `root` user and sometimes need to know which user account the dev container will be used with. 12 | 13 | (The dev container user can be configured through the `remoteUser` property in the devcontainer.json. If that is not set, the container user will be used.) 14 | 15 | ## Proposal 16 | 17 | Pass `_REMOTE_USER` and `_CONTAINER_USER` environment variables to the features scripts with `_CONTAINER_USER` being the container's user and `_REMOTE_USER` being the configured `remoteUser`. If no `remoteUser` is configured, `_REMOTE_USER` is set to the same value as `_CONTAINER_USER`. 18 | 19 | Additionally the home folders of the two users are passed to the feature scripts as `_REMOTE_USER_HOME` and `_CONTAINER_USER_HOME` environment variables. 20 | 21 | ## Notes 22 | 23 | - The container user can be set with `containerUser` in the devcontainer.json and image metadata, `user` in the docker-compose.yml, `USER` in the Dockerfile and can be passed down from the base image. 24 | -------------------------------------------------------------------------------- /proposals/build-options.md: -------------------------------------------------------------------------------- 1 | # [Proposal] Allow additional cli options to pass to the build command 2 | 3 | Related to: 4 | - https://github.com/devcontainers/spec/discussions/301 5 | - https://github.com/devcontainers/spec/pull/324 6 | - https://github.com/microsoft/vscode-remote-release/issues/3545 7 | 8 | ## Goal 9 | 10 | Extend the build section of the configuration with an option to pass additional arguments via cli. 11 | 12 | ## Proposal 13 | 14 | Introduce the property `options` to the `build` property in the schema as type `Array (string)`. This field contains elements that are directly passed as cli-arguments to the `build` command. It is similar to `runArgs` property which contains cli-arguments passed to the `run` command. 15 | 16 | ### Execution 17 | 18 | When a dev container is built, all entries from the `options` are passed to the `build` command after all other options. 19 | 20 | ## Examples 21 | 22 | ### Add a host 23 | 24 | The following example adds a host-definition while the image is being built: 25 | 26 | ```jsonc 27 | { 28 | "build": { 29 | "dockerfile": "Dockerfile", 30 | "options": [ 31 | "--add-host=host.docker.internal:host-gateway" 32 | ] 33 | }, 34 | } 35 | ``` 36 | 37 | ### Use host network 38 | 39 | The following example allows to use the host network while building an image: 40 | 41 | ```jsonc 42 | { 43 | "build": { 44 | "dockerfile": "Dockerfile", 45 | "options": [ 46 | "--network=host" 47 | ] 48 | }, 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Specification Documentation 2 | 3 | The files in this folder detail the Dev Container Specification. 4 | 5 | We add any proposal to the [**proposals folder**](https://github.com/devcontainers/spec/tree/main/proposals), only if the proposal is accepted. It stays in that folder until the implementation is in progress. Once code/schema changes are released, we move it into the [**specs folder**](https://github.com/devcontainers/spec/tree/main/docs/specs). 6 | 7 | > **Note:** Our [contributing.md](/contributing.md) documents guidelines on contributing to the spec, as well as labels (proposal and finalization) defined for this process for GitHub issues. 8 | 9 | There are several main specs in this folder, outlining the key top-level behavior of dev containers, Templates, and Features: 10 | 11 | * [Main dev container spec](/docs/specs/devcontainer-reference.md) 12 | * [Dev container metadata reference](/docs/specs/devcontainerjson-reference.md) 13 | * [Main Templates spec](/docs/specs/devcontainer-templates.md) 14 | * [Templates distribution spec](/docs/specs/devcontainer-templates-distribution.md) 15 | * [Main Features spec](/docs/specs/devcontainer-features.md) 16 | * [Features distribution spec](/docs/specs/devcontainer-features-distribution.md) 17 | * [Tools that support the spec](/docs/specs/supporting-tools.md) 18 | 19 | The remainder of the files in this folder outline specifications for specific dev container behaviors. Each file includes links to when the proposal was first discussed and when it was merged into the Dev Container CLI or schema. 20 | -------------------------------------------------------------------------------- /docs/specs/gpu-host-requirement.md: -------------------------------------------------------------------------------- 1 | # GPU Host Requirement 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/82 5 | * CLI PR: https://github.com/devcontainers/cli/pull/173 6 | 7 | Below is the original proposal. 8 | 9 | ## Goal 10 | 11 | This proposal adds GPU support to the existing host requirements properties. 12 | - Issue: https://github.com/devcontainers/spec/issues/82 13 | - Community PR: https://github.com/devcontainers/cli/pull/173 14 | 15 | ## Proposal 16 | 17 | We propose to add a new `gpu` property to the `hostRequirements` object in the devcontainer.json schema. The property can be a boolean value, the string `optional` or an object: 18 | 19 | (Additional row for the existing table in the spec.) 20 | | Property | Type | Description | 21 | |----------|------|-------------| 22 | | `hostRequirements.gpu` 🏷️ | boolean \| 'optional' | Indicates whether or not a GPU is required. A value 'optional' indicates that might be used if available. The object is described in the table below. The default is false. For example: `"hostRequirements": "optional"` | 23 | 24 | The object value can have the following properties: 25 | 26 | | Property | Type | Description | 27 | |----------|------|-------------| 28 | | `hostRequirements.gpu.cores` 🏷️ | integer | Indicates the minimum required number of cores. For example: `"hostRequirements": { "gpu": {"cores": 2} }` | 29 | | `hostRequirements.gpu.memory` 🏷️ | string | A string indicating minimum memory requirements with a `tb`, `gb`, `mb`, or `kb` suffix. For example, `"hostRequirements": {"memory": "4gb"}` | 30 | -------------------------------------------------------------------------------- /docs/specs/secrets-support.md: -------------------------------------------------------------------------------- 1 | # First Class Secrets Support 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/219 5 | * CLI PR: https://github.com/devcontainers/cli/pull/493 6 | 7 | Below is the original proposal. 8 | 9 | ## What are secrets 10 | Secrets are variables that hold sensitive values and need to be handled securely at all times (API keys, passwords etc.). Users can change a secret's value at any time, and a conforming dev containers implementation should support dynamically changing secrets without having to rebuild the container. 11 | 12 | ## Goal 13 | 14 | Support secrets as a first class feature in dev containers implementations. 15 | 16 | This feature should consist of the ability to securely pass in the secrets, make them available for users to consume similar to remoteEnv and containerEnv, and be processed and handled securely at all times. 17 | This functionality will allow consumers to be able to use secrets more predictably and securely with their dev containers implementation. 18 | 19 | ## Motivation 20 | 21 | Today many consumers pass secret variables as `remoteEnv`, since there are no other mechanisms to pass them explicitly as secrets. The dev containers reference implementation do not (and need not) treat `remoteEnv` as secrets. Having explicit support for secrets will help eliminate security threats such as leaking secrets, as well as in improving customer confidence. 22 | 23 | ## Proposal 24 | 25 | A [supporting tool](https://containers.dev/supporting#tools) (e.g. the [dev container CLI reference implementation](https://github.com/devcontainers/cli)) should behave according to the following properties: 26 | 27 | 1. Ability to pass secrets to commands 28 | 2. Apply/use secrets similar to `remoteEnv` 29 | 3. Securely handle secrets 30 | 31 | ### Passing secrets in 32 | Secrets are not part of dev containers specification and we do not expect users to store secrets inside `devcontainer.json` file. A conforming implementation should provide a secure mechanism to pass secrets, such as a secrets file, Windows credential manager, Mac keychain, Azure keyvault etc. for example. 33 | 34 | #### **Example** 35 | 36 | Using a file to pass in the secrets can be one of the simple approaches to adopt. In this example the supporting tool can input secrets in a JSON file format. 37 | 38 | ```json 39 | { 40 | "API_KEY": "adsjhsd6dfwdjfwde7edwfwedfdjedwf7wedfwe", 41 | "NUGET_CONFIG": "\n \n \n", 42 | "PASSWORD": "Simple Passwords" 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /docs/specs/declarative-secrets.md: -------------------------------------------------------------------------------- 1 | # Declarative Secrets 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/198, https://github.com/devcontainers/spec/issues/216 5 | * Schema PR: https://github.com/devcontainers/spec/pull/303 6 | 7 | Below is the original proposal. 8 | 9 | ## Motivation 10 | 11 | Various projects exist in the wild that require various secrets for them to run properly. Examples include: 12 | 13 | - https://github.com/lostintangent/codespaces-langchain 14 | - https://github.com/openai/openai-quickstart-python 15 | - https://github.com/openai/openai-quickstart-node 16 | 17 | Today these projects have to include specific instructions (e.g. in their README) telling users where to procure what they need to run and then how to set it up as a secret or add it as an environment variable. This currently acts as an impediment to adoption and promotion of dev containers for these projects. 18 | 19 | ## Goal 20 | 21 | Simplify using dev containers for these kinds of projects by supporting secrets as a first-class part of the dev container creation flow. 22 | 23 | ## Proposal 24 | 25 | Add an optional `secrets` property to the `devContainer.base.schema.json`. This will be used to declare the secrets needed within the dev container. 26 | 27 | Property | Type | Description 28 | --- | --- | --- 29 | `secrets` | `object` | The keys of this object are the names of the secrets that are in use. Keys should be [valid Linux environment variable names](https://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html). 30 | 31 | The `secrets` property contains a map of secret names and details about those secrets. These `secrets` are recommended to the user but are not _required_ for creation. All properties are optional. 32 | 33 | Property | Type | Description 34 | --- | --- | --- 35 | `description` | `string` | A brief description of the secret. 36 | `documentationUrl` | `string` | A URL pointing to where the user can obtain more information about the secret. For example where to find docs on provisioning an API key for a service. 37 | 38 | ## Example 39 | 40 | ```json 41 | { 42 | "image": "mcr.microsoft.com/devcontainers/base:bullseye", 43 | "secrets": { 44 | "CHAT_GPT_API_KEY": { 45 | "description": "I'm your super cool API key for ChatGPT.", 46 | "documentationUrl": "https://openai.com/api/" 47 | }, 48 | "STABLE_DIFFUSION_API_KEY": {} 49 | } 50 | } 51 | ``` 52 | 53 | This example would declare that this dev container wants the user to provide two secrets. The `CHAT_GPT_API_KEY` secret also provides some additional metadata that clients can use in displaying a user experience to provide that secret. The `STABLE_DIFFUSION_API_KEY` skips that metadata. 54 | 55 | Implementations _may_ inject these secrets into the container as environment variables. 56 | 57 | ## Possible Future Extensions 58 | 59 | These are **out of scope** for this proposal but the following has been discussed in relation: 60 | 61 | 1. Inclusion of a `type` field per secret. The default, which we are assuming and leveraging here, would be `"environmentVariable"`. This would include an option to specify `"reference"` and then reference the provided secrets in other parts of the dev container. 62 | 2. Prescriptions of _how_ the secrets are injected into the dev container. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Development Containers 2 | 3 | This repository is for the Development Container Specification. You can check out the spec on our website https://containers.dev/ too. 4 | 5 | A development container allows you to use a container as a full-featured development environment. It can be used to run an application, to separate tools, libraries, or runtimes needed for working with a codebase, and to aid in continuous integration and testing. 6 | 7 | The Development Container Specification seeks to find ways to enrich existing formats with common development specific settings, tools, and configuration while still providing a simplified, un-orchestrated single container option – so that they can be used as coding environments or for continuous integration and testing. 8 | 9 | ![Stages of container-based development, from development to deployment](images/dev-container-stages.png) 10 | 11 | The first format in the specification, `devcontainer.json`, was born out of necessity. It is a structured JSON with Comments (jsonc) metadata format that tools can use to store any needed configuration required to develop inside of local or cloud-based containerized coding. 12 | 13 | We envision that this same structured data can be embedded in images and other formats – all while retaining a common object model for consistent processing. For example, some of this same metadata can be added to a `devcontainer.metadata` image label to tie settings directly to a container image. 14 | 15 | Beyond repeatable setup, these same development containers provide consistency to avoid environment specific problems across developers and centralized build and test automation services. You can use the [open-source CLI reference implementation](https://github.com/devcontainers/cli) either directly or integrated into product experiences to use the structured metadata to deliver these benefits. It currently supports integrating with Docker Compose and a simplified, un-orchestrated single container option – so that they can be used as coding environments or for continuous integration and testing. 16 | 17 | A GitHub Action and an Azure DevOps Task are available in [devcontainers/ci](https://github.com/devcontainers/ci) for running a repository's dev container in continuous integration (CI) builds. This allows you to reuse the same setup that you are using for local development to also build and test your code in CI. 18 | 19 | ### Spec content 20 | 21 | You may review the specification in the [docs/specs folder](https://github.com/devcontainers/spec/tree/main/docs/specs) of this repo. 22 | 23 | You may also review active proposals in the [proposals folder](https://github.com/devcontainers/spec/tree/main/proposals). 24 | 25 | Images used in this repo will be contained in the [images folder](/images). The icon for the [dev container GitHub org](https://github.com/devcontainers) is from the [Fluent icon library](https://github.com/microsoft/fluentui-system-icons/blob/master/assets/Cube/SVG/ic_fluent_cube_32_filled.svg). 26 | 27 | ## Contributing and Feedback 28 | 29 | If you are interested in contributing, please check out the [How to Contribute](contributing.md) document, open an issue, or [join our community Slack channel](https://aka.ms/dev-container-community). 30 | 31 | Please report issues in the following repositories: 32 | 33 | - Spec-maintained Features and Templates: [devcontainers/features](https://github.com/devcontainers/features), [devcontainers/templates](https://github.com/devcontainers/templates) 34 | - CLI reference implementation and non-spec related feature requests: [devcontainers/cli](https://github.com/devcontainers/cli) 35 | - GitHub Action and Azure DevOps Task: [devcontainers/ci](https://github.com/devcontainers/ci) 36 | 37 | # License 38 | 39 | License for this repository: 40 | 41 | Copyright © Microsoft Corporation All rights reserved.
42 | Creative Commons Attribution 4.0 License (International): https://creativecommons.org/licenses/by/4.0/legalcode 43 | -------------------------------------------------------------------------------- /docs/specs/devcontainer-lockfile.md: -------------------------------------------------------------------------------- 1 | # Lockfiles 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/236 5 | * CLI PR: https://github.com/devcontainers/cli/issues/564 6 | 7 | Below is the original proposal. 8 | 9 | ## Goal 10 | 11 | Introduce a lockfile that records the exact version, download information and checksums for each feature listed in the devcontainer.json. 12 | 13 | This will allow for: 14 | - Improved reproducibility of image builds (installing "latest" of a tool will still have different outcomes as the tool publishes new releases). 15 | - Improved cachability of image builds (image cache checksums will remain stable when the lockfile pins a feature to a particular version). 16 | - Improved security by detecting when a feature's release artifact changes after its checksum was first recorded in the lockfile ("trust on first use"). 17 | 18 | ## Proposal 19 | 20 | (The following is inspired by NPM's `package-lock.json` and Yarn's `yarn.lock`.) 21 | 22 | Each feature is recorded with the identifier and version it is referred to in the devcontainer.json as its key and the following properties as its values: 23 | - `resolved`: 24 | - OCI feature: A qualified feature id with the sha256 hash (not the version number). 25 | - tarball feature: The `https:` URL used to download the feature. 26 | - `version`: The full version number. 27 | - `integrity`: `sha256:` followed by the hex encoded SHA-256 checksum of the download artifact. 28 | - `dependsOn`: An array of feature identifiers equal to the feature's `dependsOn` keys in its `devcontainer-feature.json` including any version or checksum suffix. If the array is empty, this property can be omitted. For every feature listed here, the lockfile will also have a feature record. 29 | 30 | The feature identifiers recorded as keys and in the `dependsOn` arrays are converted to lowercase to simplify lookups and comparisons. Note that the `devcontainer.json` and `devcontainer-features.json` may refer to the same features with different casing because these identifiers are not case-senstive. 31 | 32 | Local features and the deprecated GitHub releases features are not recorded in the lockfile. 33 | 34 | The lockfile is named `devcontainer-lock.json`, is located in the same folder as the `devcontainer.json` and contains a JSON object with a `"features"` property holding the above keys. 35 | 36 | Example: 37 | 38 | ```jsonc 39 | { 40 | "features": { 41 | "ghcr.io/devcontainers/features/node:1": { 42 | "version": "1.0.4", 43 | "resolved": "ghcr.io/devcontainers/features/node@sha256:567d704b3f4d3eca3acee51ded7c460a8395436d135d53d1175fb565daff42b8", 44 | "integrity": "sha256:567d704b3f4d3eca3acee51ded7c460a8395436d135d53d1175fb565daff42b8" 45 | }, 46 | "https://mycustomdomain.com/devcontainer-feature-myfeature.tgz": { 47 | "version": "1.2.3", 48 | "resolved": "https://mycustomdomain.com/devcontainer-feature-myfeature.tgz", 49 | "integrity": "sha256:567d704b3f4d3eca3acee51ded7c460a8395436d135d53d1175fb565daff42b8" 50 | } 51 | } 52 | } 53 | ``` 54 | 55 | Example with dependency: 56 | 57 | ```jsonc 58 | { 59 | "features": { 60 | "ghcr.io/codspace/dependson/a": { 61 | "version": "1.2.1", 62 | "resolved": "ghcr.io/codspace/dependson/a@sha256:932027ef71da186210e6ceb3294c3459caaf6b548d2b547d5d26be3fc4b2264a", 63 | "integrity": "sha256:932027ef71da186210e6ceb3294c3459caaf6b548d2b547d5d26be3fc4b2264a", 64 | "dependsOn": [ 65 | "ghcr.io/codspace/dependson/e:2" 66 | ] 67 | }, 68 | "ghcr.io/codspace/dependson/e:2": { 69 | "version": "2.3.4", 70 | "resolved": "ghcr.io/codspace/dependson/e@sha256:9f36f159c70f8bebff57f341904b030733adb17ef12a5d58d4b3d89b2a6c7d5a", 71 | "integrity": "sha256:9f36f159c70f8bebff57f341904b030733adb17ef12a5d58d4b3d89b2a6c7d5a" 72 | } 73 | } 74 | } 75 | ``` 76 | -------------------------------------------------------------------------------- /docs/specs/devcontainer-id-variable.md: -------------------------------------------------------------------------------- 1 | # Dev Container ID 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/62 5 | * CLI PR: https://github.com/devcontainers/cli/pull/242 6 | 7 | Below is the original proposal. 8 | 9 | ## Goal 10 | 11 | Allow features to refer to an identifier that is unique to the dev container they are installed into and that is stable across rebuilds. 12 | 13 | E.g., the `docker-in-docker` feature needs a way to mount a volume per dev container. 14 | 15 | ## Proposal 16 | 17 | The identifier will be referred to as `${devcontainerId}` in the devcontainer.json and the feature metadata and that will be replaced with the dev container's id. It should only be used in parts of the configuration and metadata that is not used for building the image because that would otherwise prevent pre-building the image at a time when the dev container's id is not known yet. Excluding boolean, numbers and enum properties the properties supporting `${devcontainerId}` in the devcontainer.json are: `name`, `runArgs`, `initializeCommand`, `onCreateCommand`, `updateContentCommand`, `postCreateCommand`, `postStartCommand`, `postAttachCommand`, `workspaceFolder`, `workspaceMount`, `mounts`, `containerEnv`, `remoteEnv`, `containerUser`, `remoteUser`, `customizations`. Excluding boolean, numbers and enum properties the properties supporting `${devcontainerId}` in the feature metadata are: `entrypoint`, `mounts`, `customizations`. 18 | 19 | Implementations can choose how to compute this identifier. They must ensure that it is unique among other dev containers on the same Docker host and that it is stable across rebuilds of dev containers. The identifier must only contain alphanumeric characters. We describe a way to do this below. 20 | 21 | ### Label-based Implementation 22 | 23 | The following assumes that a dev container can be identified among other dev containers on the same Docker host by a set of labels on the container. Implementations may choose to follow this approach. 24 | 25 | The identifier is derived from the set of container labels uniquely identifying the dev container. It is up to the implementation to choose these labels. For example, if the dev container is based on a local folder, the label could be named `devcontainer.local_folder` and have the local folder's path as its value. 26 | 27 | For example, the [`ghcr.io/devcontainers/features/docker-in-docker` feature](https://github.com/devcontainers/features/blob/main/src/docker-in-docker/devcontainer-feature.json) could use the dev container id with: 28 | 29 | ```jsonc 30 | { 31 | "id": "docker-in-docker", 32 | "version": "1.0.4", 33 | // ... 34 | "mounts": [ 35 | { 36 | "source": "dind-var-lib-docker-${devcontainerId}", 37 | "target": "/var/lib/docker", 38 | "type": "volume" 39 | } 40 | ] 41 | } 42 | ``` 43 | 44 | ### Label-based Computation 45 | 46 | - Input the labels as a JSON object with the object's keys being the label names and the object's values being the labels' values. 47 | - To ensure implementations get to the same result, the object keys must be sorted and any optional whitespace outside of the keys and values must be removed. 48 | - Compute a SHA-256 hash from the UTF-8 encoded input string. 49 | - Use a base-32 encoded representation left-padded with '0' to 52 characters as the result. 50 | 51 | JavaScript implementation taking an object with the labels as argument and returning a string as the result: 52 | ```js 53 | const crypto = require('crypto'); 54 | 55 | function uniqueIdForLabels(idLabels) { 56 | const stringInput = JSON.stringify(idLabels, Object.keys(idLabels).sort()); // sort properties 57 | const bufferInput = Buffer.from(stringInput, 'utf-8'); 58 | 59 | const hash = crypto.createHash('sha256') 60 | .update(bufferInput) 61 | .digest(); 62 | 63 | const uniqueId = BigInt(`0x${hash.toString('hex')}`) 64 | .toString(32) 65 | .padStart(52, '0'); 66 | return uniqueId; 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute to the Dev Container Specification 2 | 3 | We're excited for your contributions to the dev container specification! This document outlines how you can get involved. 4 | 5 | ## Contribution approaches 6 | 7 | If you'd like to contribute a change or addition to the spec, you may follow the guidance below: 8 | - Propose the change via an [issue](https://github.com/microsoft/dev-container-spec/issues) in this repository. Try to get early feedback before spending too much effort formalizing it. 9 | - More formally document the proposed change in terms of properties and their semantics. Look to format your proposal like our [devcontainer.json reference](https://aka.ms/devcontainer.json), which is a JSON with Comments (jsonc) format. 10 | 11 | Here is a sample: 12 | 13 | | Property | Type | Description | 14 | |----------|------|-------------| 15 | | `image` | string | **Required** when [using an image](/docs/remote/create-dev-container.md#using-an-image-or-dockerfile). The name of an image in a container registry ([DockerHub](https://hub.docker.com), [GitHub Container Registry](https://docs.github.com/packages/guides/about-github-container-registry), [Azure Container Registry](https://azure.microsoft.com/services/container-registry/)) that VS Code and other `devcontainer.json` supporting services / tools should use to create the dev container. | 16 | 17 | - PRs to the [schema](https://github.com/devcontainers/spec/blob/main/schemas/devContainer.base.schema.json), i.e code or shell scripts demonstrating approaches for implementation. 18 | 19 | Once there is discussion on your proposal, please also open and link a PR to update the [devcontainer.json reference doc](https://github.com/microsoft/vscode-docs/blob/main/docs/remote/devcontainerjson-reference.md). When your proposal is merged, the docs will be kept up-to-date with the latest spec. 20 | 21 | ### Contributing tool-specific support 22 | 23 | Tool-specific properties are contained in namespaces in the `"customizations"` property. For instance, VS Code specific properties are formatted as: 24 | 25 | ```bash 26 | // Configure tool-specific properties. 27 | "customizations": { 28 | // Configure properties specific to VS Code. 29 | "vscode": { 30 | // Set *default* container specific settings.json values on container create. 31 | "settings": {}, 32 | 33 | // Additional VS Code specific properties... 34 | } 35 | }, 36 | ``` 37 | 38 | You may propose adding a new namespace for a specific tool, and any properties specific to that tool. 39 | 40 | ## Formatting Guidelines 41 | 42 | When contributing an official doc or referencing dev containers in your projects, please consider the following guidelines: 43 | 44 | - Refer to the spec as the "Development Container Specification" 45 | - All capital letters 46 | - Singular "Container" rather than plural "Containers" 47 | - The term "dev container" shouldn't be capitalized on its own 48 | - It should only be capitalized when referring to an official tool title, like the VS Code Dev Containers extension 49 | - Signify `devcontainer.json` is a file type through backticks 50 | - Features and Templates should always be capitalized 51 | - Refer to the CLI as the "Dev Container CLI" (note the caps) 52 | - Use bolding for emphasis sprinkled throughout sections, rather than try to use it to always bold certain terms 53 | 54 | ## Review process 55 | 56 | We use the following [labels](https://github.com/microsoft/dev-container-spec/labels): 57 | 58 | - `proposal`: Issues under discussion, still collecting feedback. 59 | - `finalization`: Proposals we intend to make part of the spec. 60 | 61 | [Milestones](https://github.com/microsoft/dev-container-spec/milestones) use a "month year" pattern (i.e. January 2022). If a finalized proposal is added to a milestone, it is intended to be merged during that milestone. 62 | 63 | ## Community Engagement 64 | There are several additional options to engage with the dev container community, such as asking questions, providing feedback, or engaging on how your team may use or contribute to dev containers: 65 | - [GitHub Discussions](https://github.com/devcontainers/spec/discussions): This is a great opportunity to connect with the community and maintainers of this project, without the requirement of contributing a change to the actual spec (which we see more in issues and PRs) 66 | - [Community Slack channel](https://aka.ms/dev-container-community): This is a great opportunity to connect with the community and maintainers 67 | - You can always check out the issues and PRs (and contribute new ones) across the repos in the [Dev Containers GitHub org](https://github.com/devcontainers) too! 68 | -------------------------------------------------------------------------------- /docs/specs/features-contribute-lifecycle-scripts.md: -------------------------------------------------------------------------------- 1 | # Allow Dev Container Features to contribute lifecycle scripts 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/60, https://github.com/devcontainers/spec/issues/181 5 | * CLI PR: https://github.com/devcontainers/cli/pull/390 6 | 7 | Below is the original proposal. 8 | 9 | ## Goal 10 | 11 | Allow Feature authors to provide lifecycle hooks for their Features during a dev container build. 12 | 13 | ## Proposal 14 | 15 | Introduce the following properties to [devcontainer-feature.json](https://containers.dev/implementors/features/#devcontainer-feature-json-properties), mirroring the behavior and syntax of the `devcontainer.json` lifecycle hooks. 16 | 17 | - "onCreateCommand" 18 | - "updateContentCommand" 19 | - "postCreateCommand" 20 | - "postStartCommand" 21 | - "postAttachCommand" 22 | 23 | Note that `initializeCommand` is omitted, pending further discussions around a secure design. 24 | 25 | As with all lifecycle hooks, commands are executed from the context (cwd) of the [project workspace folder](https://containers.dev/implementors/spec/#project-workspace-folder). 26 | 27 | > **Note:** To use any assets (a script, etc...) embedded within a Feature in a lifecycle hook property, it is the Feature author's reponsibility to copy that assert to somewhere on the container where it will persist (outside of `/tmp`.) Implementations are not required to persist Feature install scripts beyond the initial build. 28 | 29 | All other semantics match the existing [Lifecycle Scripts](https://containers.dev/implementors/json_reference/#lifecycle-scripts) and [lifecycle script parallel execution](https://containers.dev/implementors/spec/#parallel-exec) behavior exactly. 30 | 31 | ### Execution 32 | 33 | When a dev container is brought up, for each lifecycle hook, each Feature that contributes a command to a lifecycle hook shall have the command executed in sequence, following the same execution order as outlined in [Feature installation order](https://containers.dev/implementors/features/#installation-order), and always before any user-provided lifecycle commands. 34 | 35 | ## Examples 36 | 37 | 38 | ### Executing a script in the workspace folder 39 | 40 | The follow example illustrates contributing an `onCreateCommand` and `postCreateCommand` script to `featureA`. At each lifecycle hook during the build, the provided script will be executed in the [project workspace folder](https://containers.dev/implementors/spec/#project-workspace-folder), following the same semantics as [user-defined lifecycle hooks](https://containers.dev/implementors/json_reference/#lifecycle-scripts). 41 | 42 | ```jsonc 43 | { 44 | "id": "featureA", 45 | "version": "1.0.0", 46 | "onCreateCommand": "myOnCreate.sh && myOnCreate2.sh", 47 | "postCreateCommand": "myPostCreate.sh", 48 | "postAttachCommand": { 49 | "command01": "myPostAttach.sh arg01", 50 | "command02": "myPostAttach.sh arg02", 51 | }, 52 | } 53 | 54 | ``` 55 | 56 | ### Executing a script bundled with the Feature 57 | 58 | The following example illustrates executing a `postCreateCommand` script bundled with the Feature. 59 | 60 | ```jsonc 61 | { 62 | "id": "featureB", 63 | "version": "1.0.0", 64 | "postCreateCommand": "/usr/myDir/bundledScript.sh", 65 | "installsAfter": [ 66 | "featureA" 67 | ] 68 | } 69 | ``` 70 | 71 | The `install.sh` will need to move this script to `/usr/myDir`. 72 | 73 | ``` 74 | #!/bin/sh 75 | 76 | cp ./bundleScript /usr/myDir 77 | ... 78 | ... 79 | ``` 80 | 81 | Given this example, `featureB`'s file structure would look something like: 82 | 83 | ``` 84 | . 85 | ├── src 86 | │ ├── featureB 87 | │ │ ├── bundledScript.sh 88 | │ │ ├── devcontainer-feature.json 89 | │ │ └── install.sh 90 | ``` 91 | 92 | ### Installation 93 | 94 | Given the following `devcontainer.json` and the two example Features above. 95 | 96 | ```jsonc 97 | { 98 | "image": "ubuntu", 99 | "features": { 100 | "featureA": {}, 101 | "featureB": {}, 102 | }, 103 | "postCreateCommand": "userPostCreate.sh", 104 | "postAttachCommand": { 105 | "server": "npm start", 106 | "db": ["mysql", "-u", "root", "-p", "my database"] 107 | }, 108 | } 109 | ``` 110 | 111 | The following timeline of events would occur. 112 | 113 | > Note that: 114 | > 115 | >1. Each bullet point below is _blocking_. No subsequent lifecycle commands shall proceed until the current command completes. 116 | > 2. If one of the lifecycle scripts fails, any subsequent scripts will not be executed. For instance, if a given `postCreate` command fails, the `postStart` hook and any following hooks will be skipped. 117 | > 118 | 119 | - `featureA`'s onCreateCommand 120 | - `featureA`'s postCreateCommand 121 | - `featureB`'s postCreateCommand 122 | - The user's postCreateCommand 123 | - `featureA`'s postAttachCommand **(parallel syntax, each command running in parallel)** 124 | - The user's postAttachCommand **(parallel syntax, each command running in parallel)** 125 | 126 | Suppose `featureB`'s postCreateCommand exited were to exit unsuccessfully (non-zero exit code). In this case, the `postAttachCommand` will never fire. 127 | -------------------------------------------------------------------------------- /docs/specs/image-metadata.md: -------------------------------------------------------------------------------- 1 | # Image Metadata 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/18 5 | * CLI PR: https://github.com/devcontainers/cli/pull/188 6 | 7 | Below is the original proposal. 8 | 9 | ## Goal 10 | 11 | Record dev container config and feature metadata in prebuilt images, such that, the image and the built-in features can be used with a devcontainer.json (image-, Dockerfile- or Docker Compose-based) that does not repeat the dev container config or feature metadata. Other tools should be able to record the same metadata without necessarily using features themselves. 12 | 13 | Current dev container config that can be recorded in the image: `mounts`, `onCreateCommand`, `updateContentCommand`, `postCreateCommand`, `postStartCommand`, `postAttachCommand`, `customizations`, `remoteUser`, `userEnvProbe`, `remoteEnv`, `containerEnv`, `overrideCommand`, `portsAttributes`, `otherPortsAttributes`, `forwardPorts`, `shutdownAction`, `updateRemoteUserUID` and `hostRequirements`. 14 | 15 | Current feature metadata relevant for using the feature when it is already part of the image: `mounts`, `init`, `privileged`, `capAdd`, `securityOpt`, `entrypoint` and `customizations`. 16 | 17 | We can add to these lists as we add more properties to the dev container configuration and the feature metadata. 18 | 19 | ## Proposal 20 | 21 | We propose to add metadata to the image with the following structure using one entry per feature and devcontainer.json (see table below for the full list): 22 | 23 | ``` 24 | [ 25 | { 26 | "id"?: string, 27 | "init"?: boolean, 28 | "privileged"?: boolean, 29 | "capAdd"?: string[], 30 | "securityOpt"?: string[], 31 | "entrypoint"?: string, 32 | "mounts"?: [], 33 | ... 34 | "customizations"?: { 35 | ... 36 | } 37 | }, 38 | ... 39 | ] 40 | ``` 41 | 42 | To simplify adding this metadata for other tools, we also support having a single top-level object with the same properties. 43 | 44 | The metadata is added to the image as a `devcontainer.metadata` label with a JSON string value representing the above array or single object. 45 | 46 | ## Merge Logic 47 | 48 | To apply the metadata together with a user's devcontainer.json at runtime the following merge logic by property is used. The table also notes which properties are currently supported coming from the devcontainer.json and which from the feature metadata, this will change over time as we add more properties. 49 | 50 | | Property | Type/Format | Merge Logic | devcontainer.json | Feature Metadata | 51 | | -------- | ----------- | ----------- | :---------------: | :--------------: | 52 | | `id` | E.g., `ghcr.io/devcontainers/features/node:1` | Not merged. | | x | 53 | | `init` | `boolean` | `true` if at least one is `true`, `false` otherwise. | x | x | 54 | | `privileged` | `boolean` | `true` if at least one is `true`, `false` otherwise. | x | x | 55 | | `capAdd` | `string[]` | Union of all `capAdd` arrays without duplicates. | x | x | 56 | | `securityOpt` | `string[]` | Union of all `securityOpt` arrays without duplicates. | x | x | 57 | | `entrypoint` | `string` | Collected list of all entrypoints. | | x | 58 | | `mounts` | `(string \| { type, src, dst })[]` | Collected list of all mountpoints. Conflicts: Last source wins. | x | x | 59 | | `onCreateCommand` | `string \| string[]` | Collected list of all onCreateCommands. | x | | 60 | | `updateContentCommand` | `string \| string[]` | Collected list of all updateContentCommands. | x | | 61 | | `postCreateCommand` | `string \| string[]` | Collected list of all postCreateCommands. | x | | 62 | | `postStartCommand` | `string \| string[]` | Collected list of all postStartCommands. | x | | 63 | | `postAttachCommand` | `string \| string[]` | Collected list of all postAttachCommands. | x | | 64 | | `waitFor` | enum | Last value wins. | x | | 65 | | `customizations` | Object of tool-specific customizations. | Merging is left to the tools. | x | x | 66 | | `containerUser` | `string` | Last value wins. | x | | 67 | | `remoteUser` | `string` | Last value wins. | x | | 68 | | `userEnvProbe` | `string` (enum) | Last value wins. | x | | 69 | | `remoteEnv` | Object of strings. | Per variable, last value wins. | x | | 70 | | `containerEnv` | Object of strings. | Per variable, last value wins. | x | | 71 | | `overrideCommand` | `boolean` | Last value wins. | x | | 72 | | `portsAttributes` | Map of ports to attributes. | Per port (not per port attribute), last value wins. | x | | 73 | | `otherPortsAttributes` | Port attributes. | Last value wins (not per port attribute). | x | | 74 | | `forwardPorts` | `(number \| string)[]` | Union of all ports without duplicates. Last one wins (when mapping changes). | x | | 75 | | `shutdownAction` | `string` (enum) | Last value wins. | x | | 76 | | `updateRemoteUserUID` | `boolean` | Last value wins. | x | | 77 | | `hostRequirements` | `cpus`, `memory`, `storage` | Max value wins. | x | | 78 | 79 | Variables in string values will be substituted at the time the value is applied. When the order matters, the devcontainer.json is considered last. 80 | 81 | ## Additional devcontainer.json Properties 82 | 83 | We are adding support for `mounts`, `containerEnv`, `containerUser`, `init`, `privileged`, `capAdd`, and `securityOpt` to the devcontainer.json (also with Docker Compose) the same way these properties are already supported in the feature metadata. 84 | 85 | ## Notes 86 | 87 | - Passing the label as a `LABEL` instruction in the Dockerfile: 88 | - The size limit on Dockerfiles is around 1.3MB. The line length is limited to 65k characters. 89 | - Using one line per feature should allow for making full use of these limits. 90 | - Passing the label as a command line argument: 91 | - There is no size limit documented for labels, but the daemon returns an error when the request header is >500kb. 92 | - The 500kb limit is shared, so we cannot use a second label in the same build to avoid it. 93 | - If/when this becomes an issue we could embed the metadata as a file in the image (e.g., with a label indicating it). 94 | -------------------------------------------------------------------------------- /proposals/features-library.md: -------------------------------------------------------------------------------- 1 | # Sharing code between Dev Container Features 2 | 3 | ref: https://github.com/devcontainers/spec/issues/129 4 | 5 | # Motivation 6 | 7 | The current model for authoring Features encourages significant copy and paste between individual Features. Most of the Features published under the `devcontainers/features` namespace contain approximately 100 lines of [identical helper functions](https://github.com/devcontainers/features/blob/main/src/azure-cli/install.sh#L29-L164) before the first line of the script is executed. The process of maintaining these helper functions is tedious, error-prone, and leads to less readable Features. 8 | 9 | Additionally, [members of the Feature authoring community have expressed interest in sharing code between Features](https://github.com/orgs/devcontainers/discussions/10). Exploring the source code of self-published Features, it is evident that many authors have copy/pasted code from other Features. This is a sign that there is a need for a more efficient way to share code between Features. 10 | 11 | # Goal 12 | 13 | Provide a generic and simple way to share code between Features. 14 | 15 | # Proposals 16 | 17 | ## [Proposal A] Add: `include` property to `devcontainer-feature.json` 18 | 19 | Add an `include` property to the `devcontainer-feature.json`. This will be honored during the Feature [packaging stage](https://containers.dev/implementors/features-distribution/#packaging). 20 | 21 | The contents of the provided relative path is copied into the packaged Feature archive. Files or directories are recursively copied into the archive following the same directory structure as in the source code. 22 | 23 | The relative path must not escape the root directory - if this is attempted, the packaging stage will fail. 24 | 25 | Property | Type | Description 26 | --- | --- | --- 27 | `include` | `string[]` | An array of paths relative to the directory containing this `devcontainer-feature.json`. If the element is a folder, it is copied recursively. Must be prefixed with `.` or `..` to indicate the provided string is relative path. 28 | 29 | ### Example 30 | 31 | ```json 32 | { 33 | "name": "featureA", 34 | "version": "0.0.1", 35 | "include": [ 36 | "../../utils/", 37 | "../../company-welcome-message.txt" 38 | ] 39 | } 40 | ``` 41 | 42 | ## [Proposal B] Change: Structure of packaged Feature 43 | 44 | Change the file structure of the packaged Feature to mirror the directory structure of the source code. This will simplify the implementation of **Proposal A** and keep the relative paths consistent before and after packaging. 45 | 46 | When running the packaging step, each Feature is packaged separately under `./src/`. Other included directories will be copied into the root of the packaged artifact as indicated in **Proposal A**. 47 | 48 | An implementation should resolve the `devcontainer-feature.json` by checking for its presence in the following order of precedence: 49 | 50 | - `./src//devcontainer-feature.json` 51 | - `devcontainer-feature.json` 52 | 53 | From here forward, the proposed format will be used during the packaging step. For backwards compatibility, the existing format (with a `devcontainer-feature.json` at the top level) will be supported. 54 | 55 | ### Example 56 | 57 | Given this example repository containing a collection of Features. 58 | 59 | ``` 60 | . 61 | ├── images 62 | │ ├── 1.png 63 | │ ├── 2.png 64 | ├── company-welcome-message.txt 65 | ├── utils 66 | | ├── common.sh 67 | │ └── helpers 68 | │ ├── a.sh 69 | │ └── ... 70 | | 71 | ├── src 72 | │ ├── featureA 73 | │ │ ├── devcontainer-feature.json 74 | │ │ ├── install.sh 75 | │ │ └── ... 76 | │ ├── featureB 77 | │ │ ├── devcontainer-feature.json 78 | │ │ └── install.sh 79 | │ │ └── ... 80 | | ├── ... 81 | │ │ ├── devcontainer-feature.json 82 | │ │ └── install.sh 83 | │ │ └── ... 84 | ├── ... 85 | ``` 86 | 87 | When packaging Feature A (shown above in **Proposal A**), the resulting published archive will be structured as follows: 88 | 89 | ``` 90 | . 91 | ├── company-welcome-message.txt 92 | ├── utils 93 | | ├── common.sh 94 | │ └── helpers 95 | │ ├── a.sh 96 | │ └── ... 97 | | 98 | ├── src 99 | │ ├── featureA 100 | │ │ ├── devcontainer-feature.json 101 | │ │ ├── install.sh 102 | │ │ └── ... 103 | ``` 104 | 105 | The packaging step recursively copies the contents of the `utils` folder into the resulting archive. Additionally, the `company-welcome-message.txt` is packaged and distributed with the Feature. 106 | 107 | Note that the `images` folder is not included in the packaged Feature. This is because the `images` folder is not included in the `include` property of the `devcontainer-feature.json` file. 108 | 109 | #### Using an included script in a Feature 110 | 111 | The following example shows how a Feature could include a `utils` folder that contains a `common.sh` file. 112 | 113 | ```bash 114 | # utils/common.sh 115 | function common_function() { 116 | echo "Hello, '$1'" 117 | } 118 | ``` 119 | 120 | ```bash 121 | # src/featureA/install.sh 122 | 123 | # Include common functions 124 | source "../../utils/common.sh" 125 | 126 | # Use common function 127 | common_function "devcontainers" 128 | ``` 129 | 130 | ----- 131 | 132 | # Possible Extensions 133 | 134 | This section provides hints to possible future work that could extend the proposal above. These are not part of the proposal, but are provided to help the community understand the potential future impact of this proposal. 135 | 136 | ## Distributing shared library Features 137 | 138 | In an effort to reduce the need for authors to copy/paste auxillary scripts between Feature namespaces, provide the ability to publish "library" Features. These Features would be published [following the Feature distribution spec](https://containers.dev/implementors/features-distribution/#distribution) under a new manifest type. 139 | 140 | A "library" can be included in a Feature's `include` property as an alternative to a relative path. By itself, a "library" Feature would not be installable. 141 | 142 | ```json 143 | 144 | { 145 | "name": "featureA", 146 | "version": "0.0.1", 147 | "include": [ 148 | "ghcr.io/devcontainers/features/utils:0.0.1" 149 | ] 150 | } 151 | -------------------------------------------------------------------------------- /docs/specs/features-legacyIds-deprecated-properties.md: -------------------------------------------------------------------------------- 1 | # Renaming and Deprecating Features 2 | 3 | This has now been implemented: 4 | * Discussion issue: https://github.com/devcontainers/spec/issues/146 5 | * CLI PR: https://github.com/devcontainers/cli/pull/346, https://github.com/devcontainers/cli/pull/335 6 | 7 | Below is the original proposal. 8 | 9 | ## Goal 10 | 11 | Adds support for renaming and deprecating a Feature. 12 | 13 | Adding two new properties to the [devcontainer-feature.json](../docs/specs/devcontainer-features.md#devcontainer-featurejson-properties) 👇 14 | 15 | ## 1. legacyIds 16 | 17 | | Property | Type | Description | 18 | | :--- | :--- | :--- | 19 | | `legacyIds` | array | Defaults to `[]`. Array of old IDs used to publish this Feature. The property is useful for renaming a currently published Feature within a single namespace. | 20 | 21 | ### Steps to rename a Feature 22 | 23 | 1. Update the Feature [source code](../docs/specs/features-distribution/#source-code) folder and the `id` property in the [devcontainer-feature.json properties](../docs/specs/devcontainer-features.md#devcontainer-featurejson-properties) to reflect the new `id`. Other properties (`name`, `documentationUrl`, etc.) can optionally be updated during this step. 24 | 2. Add or update the `legacyIds` property to the Feature, including the previously used `id`. 25 | 3. Bump the semantic version of the Feature. 26 | 4. Rerun the `devcontainer features publish` command, or equivalent tool that implements the [Features distribution specification](../docs/specs/features-distribution/#distribution). 27 | 28 | #### Example: Renaming a Feature 29 | 30 | Let's say we currently have a `docker-from-docker` Feature 👇 31 | 32 | Current `devcontainer-feature.json` : 33 | 34 | ```jsonc 35 | { 36 | "id": "docker-from-docker", 37 | "version": "2.0.1", 38 | "name": "Docker (Docker-from-Docker)", 39 | "documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-from-docker", 40 | .... 41 | } 42 | ``` 43 | 44 | We'd want to rename this Feature to `docker-outside-of-docker`. The source code folder of the Feature will be updated to `docker-outside-of-docker` and the updated `devcontainer-feature.json` will look like 👇 45 | 46 | ```jsonc 47 | { 48 | "id": "docker-outside-of-docker", 49 | "version": "2.0.2", 50 | "name": "Docker (Docker-outside-of-Docker)", 51 | "documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-outside-of-docker", 52 | "legacyIds": [ 53 | "docker-from-docker" 54 | ] 55 | .... 56 | } 57 | ``` 58 | 59 | **Note** - The semantic version of the Feature defined by the `version` property should be **continued** and should not be restarted at `1.0.0`. 60 | 61 | #### Changes to the Features distribution specification 62 | 63 | - [Tools implementing the Dev Container Features Distribution Specification](../docs/specs/features-distribution/#distribution) (e.g. [Dev Container CLI](https://github.com/devcontainers/cli) and [Dev Container Publish GitHub Action](https://github.com/marketplace/actions/dev-container-publish)) will dual publish the old `id`s (defined by the `legacyIds` property), and the new `id`. 64 | - The [putManifestWithTags](https://github.com/devcontainers/cli/blob/main/src/spec-configuration/containerCollectionsOCIPush.ts#L172) will be modified. The same `tgz` file for the `id` will be pushed to the `id`s mentioned by the `legacyIds` property for all the [tags](https://github.com/devcontainers/cli/blob/main/src/spec-configuration/containerCollectionsOCIPush.ts#L175). 65 | 66 | #### Supporting backwards compatibility for [`installsAfter`](../docs/specs/devcontainer-features.md#2-the-installsafter-feature-property) property 67 | 68 | - Currently the `installsAfter` property is defined as an array consisting of the Feature `id` that should be installed before the given Feature. 69 | - The Feature to be renamed could be already defined by other Feature authors in their `installsAfter` property. Renaming the `id` could change the installation order for them if the `installsAfter` property is not updated with the new `id`. In order to avoid this unexpected behavior and to support back compat, the CLI tooling will be updated to also look at the `legacyIds` property along with the `id` for determining the installation order. 70 | 71 | #### Supporting tools 72 | 73 | This property can be used by the supporting tools to indicate Feature rename in few ways 74 | - [Dev Container Publish GitHub Action](https://github.com/devcontainers/action) which auto-generates the README files can add a note with a list of old `id`s which were used to publish this Feature. 75 | - In the scenarios where Dev Configs are referencing the old `id`s, the VS Code extension hints could be enhanced to deliver this warning that the `id` was renamed to a new one. 76 | - The [containers.dev/features](https://containers.dev/features) website, and [supporting tools](https://containers.dev/supporting) like [VS Code Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) and [GitHub Codespaces](https://github.com/features/codespaces) wouldn't list the old `id`, instead list the new `id` of Features. 77 | 78 | ## 2. deprecated 79 | 80 | | Property | Type | Description | 81 | | :--- | :--- | :--- | 82 | | `deprecated` | boolean | Defaults to `false`. Indicates that the Feature is deprecated, and will not receive any further updates/support. This property is intended to be used by the supporting tools to highlight Feature deprecation. | 83 | 84 | - If this property is set to `true`, then it indicates that the Feature is deprecated and won't be receiving any further updates/support. The OCI artifacts would exist, hence, the current dev configs will continue to work. 85 | - In case of security or other ciritical updates, the Feature author could still publish a new version of the deprecated Feature by bumping the semantic version of the Feature. 86 | - This property could be used by the supporting tools to indicate Feature deprecation in few ways - 87 | - [Dev Container Publish GitHub Action](https://github.com/devcontainers/action) which auto-generates the README files can be updated to add a top-level header mentioning it's deprecation. 88 | - The [containers.dev/features](https://containers.dev/features) website, and [supporting tools](https://containers.dev/supporting) like [VS Code Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) and [GitHub Codespaces](https://github.com/features/codespaces) wouldn't list the deprecated Features. 89 | - VS Code extension hints could be enhanced to deliver this information about it's deprecation. 90 | -------------------------------------------------------------------------------- /docs/specs/devcontainer-templates-distribution.md: -------------------------------------------------------------------------------- 1 | # Distribution and Discovery of Dev Container Templates 2 | 3 | **TL;DR Check out the [quick start repository](https://github.com/devcontainers/template-starter) to get started on distributing your own Dev Container Templates.** 4 | 5 | This specification defines a pattern where community members and organizations can author and self-publish [Dev Container Templates](./devcontainer-templates.md). 6 | 7 | Goals include: 8 | 9 | - For Template authors, create a "self-service" way to publish a Template, either publicly or privately, that is not centrally controlled. 10 | - Provide the ability to standardize publishing such that supporting tools may implement their own mechanism to aid Template discoverability as they see fit. 11 | 12 | ## Source code 13 | 14 | A Template's source code is stored in a git repository. 15 | 16 | For ease of authorship and maintenance, [1..n] Templates can share a single git repository. This set of Templates is referred to as a "collection," and will share the same [`devcontainer-collection.json`](#devcontainer-collection.json) file and "namespace" (eg. `/`). 17 | 18 | > **Note:** Templates and [Features](./devcontainer-features.md) should be placed in different git repositories. 19 | 20 | Source code for a set of Templates follows the example file structure below: 21 | 22 | ``` 23 | . 24 | ├── README.md 25 | ├── src 26 | │ ├── dotnet 27 | │ │ ├── devcontainer-template.json 28 | │ │ ├── .devcontainer 29 | │ │ ├── devcontainer.json 30 | │ │ └── ... 31 | │ │ ├── ... 32 | | ├ 33 | │ ├── docker-from-docker 34 | │ │ ├── devcontainer-template.json 35 | │ │ ├── .devcontainer 36 | │ │ ├── devcontainer.json 37 | │ │ ├── Dockerfile 38 | │ │ └── ... 39 | │ │ ├── ... 40 | | ├ 41 | │ ├── go-postgres 42 | │ │ ├── devcontainer-template.json 43 | │ │ ├── .devcontainer 44 | │ │ ├── devcontainer.json 45 | │ │ ├── docker-compose.yml 46 | │ │ ├── Dockerfile 47 | │ │ └── ... 48 | │ │ ├── ... 49 | ``` 50 | 51 | ...where `src` is a directory containing a sub-folder with the name of the Template (e.g. `src/dotnet` or `src/docker-from-docker`) with at least a file named `devcontainer-template.json` that contains the Template metadata, and a `.devcontainer/devcontainer.json` that the supporting tools will drop into an existing project or folder. 52 | 53 | Each sub-directory should be named such that it matches the `id` field of the `devcontainer-template.json`. Other files can also be included in the Templates's sub-directory, and will be included during the [packaging step](#packaging) alongside the two required files. Any files that are not part of the Templates's sub-directory (e.g. outside of `src/dotnet`) will not be included in the [packaging step](#packaging). 54 | 55 | ## Versioning 56 | 57 | Each Template is individually [versioned according to the semver specification](https://semver.org/). The `version` property in the respective `devcontainer-template.json` file is parsed to determine if the Template should be republished. 58 | 59 | Tooling that handles publishing Templates will not republish Templates if that exact version has already been published; however, tooling must republish major and minor versions in accordance with the semver specification. 60 | 61 | ## Packaging 62 | 63 | Templates are distributed as tarballs. The tarball contains the entire contents of the Template sub-directory, including the `devcontainer-template.json`, `.devcontainer/devcontainer.json`, and any other files in the directory. 64 | 65 | The tarball is named `devcontainer-template-.tgz`, where `` is the Templates's `id` field. 66 | 67 | A reference implementation for packaging and distributing Templates is provided as a GitHub Action (https://github.com/devcontainers/action). 68 | 69 | ### devcontainer-collection.json 70 | 71 | The `devcontainer-collection.json` is an auto-generated metadata file. 72 | 73 | | Property | Type | Description | 74 | | :--- | :--- | :--- | 75 | | `sourceInformation` | object | Metadata from the implementing packaging tool. | 76 | | `templates` | array | The list of Templates that are contained in this collection.| 77 | 78 | Each Template's `devcontainer-template.json` metadata file is appended into the `templates` top-level array. 79 | 80 | ## Distribution 81 | 82 | There are several supported ways to distribute Templates. Distribution is handled by the implementing packaging tool such as the **[Dev Container CLI](https://github.com/devcontainers/cli)** or **[Dev Container Publish GitHub Action](https://github.com/marketplace/actions/dev-container-publish)**. 83 | 84 | A user can add a Template in to their projects as defined by the [supporting Tools](../docs/specs/supporting-tools.md#supporting-tools-and-services). 85 | 86 | ### OCI Registry 87 | 88 | An OCI registry that implements the [OCI Artifact Distribution Specification](https://github.com/opencontainers/distribution-spec) serves as the primary distribution mechanism for Templates. 89 | 90 | Each packaged Template is pushed to the registry following the naming convention `//[:version]`, where version is the major, minor, and patch version of the Template, according to the semver specification. 91 | 92 | > **Note:** `namespace` is a unique identifier for the collection of Templates and must be different than the collection of [Features](./devcontainer-features.md). There are no strict rules for `namespace`; however, one pattern is to set `namespace` equal to source repository's `/`. 93 | 94 | A custom media type `application/vnd.devcontainers` and `application/vnd.devcontainers.layer.v1+tar` are used as demonstrated below. 95 | 96 | For example, the `go` Template in the `devcontainers/templates` namespace at version `1.2.3` would be pushed to the ghcr.io OCI registry. 97 | 98 | > **Note:** The example below uses [`oras`](https://oras.land/) for demonstration purposes. A supporting tool should directly implement the required functionality from the aforementioned OCI artifact distribution specification. 99 | 100 | ```bash 101 | # ghcr.io/devcontainers/templates/go:1 102 | REGISTRY=ghcr.io 103 | NAMESPACE=devcontainers/templates 104 | TEMPLATE=go 105 | 106 | ARTIFACT_PATH=devcontainer-template-go.tgz 107 | 108 | for VERSION in 1 1.2 1.2.3 latest 109 | do 110 | oras push ${REGISTRY}/${NAMESPACE}/${TEMPLATE}:${VERSION} \ 111 | --config /dev/null:application/vnd.devcontainers \ 112 | ./${ARTIFACT_PATH}:application/vnd.devcontainers.layer.v1+tar 113 | done 114 | 115 | ``` 116 | 117 | The "namespace" is the globally identifiable name for the collection of Templates (e.g. `owner/repo` for the source code's git repository). 118 | 119 | The auto-generated `devcontainer-collection.json` is pushed to the registry with the same `namespace` as above and no accompanying `template` name. The collection file is always tagged as `latest`. 120 | 121 | ```bash 122 | # ghcr.io/devcontainers/templates 123 | REGISTRY=ghcr.io 124 | NAMESPACE=devcontainers/templates 125 | 126 | oras push ${REGISTRY}/${NAMESPACE}:latest \ 127 | --config /dev/null:application/vnd.devcontainers \ 128 | ./devcontainer-collection.json:application/vnd.devcontainers.collection.layer.v1+json 129 | ``` 130 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /docs/specs/supporting-tools.md: -------------------------------------------------------------------------------- 1 | # Supporting Tools and Services 2 | 3 | **Note: For the latest set of supporting tools, please check out https://containers.dev/supporting.** 4 | 5 | This page outlines tools and services that currently support the Development Container Specification, including the `devcontainer.json` format. A `devcontainer.json` file in your project tells tools and services that support the dev container spec how to access (or create) a dev container with a well-defined tool and runtime stack. 6 | 7 | While most [dev container properties](devcontainerjson-reference.md) apply to any supporting tool or service, a few are specific to certain tools, which are outlined below. 8 | 9 | ## Editors 10 | 11 | ### Visual Studio Code 12 | 13 | Visual Studio Code specific properties go under `vscode` inside `customizations`. 14 | 15 | 16 | ```jsonc 17 | "customizations": { 18 | // Configure properties specific to VS Code. 19 | "vscode": { 20 | // Set *default* container specific settings.json values on container create. 21 | "settings": {}, 22 | "extensions": [], 23 | } 24 | } 25 | ``` 26 | 27 | 28 | | Property | Type | Description | 29 | |----------|------|-------------| 30 | | `extensions` | array | An array of extension IDs that specify the extensions that should be installed inside the container when it is created. Defaults to `[]`. | 31 | | `settings` | object | Adds default `settings.json` values into a container/machine specific settings file. Defaults to `{}`. | 32 | 33 | Please note that the VS Code [Dev Containers](#visual-studio-code-remote---containers) extension and [GitHub Codespaces](#github-codespaces) support the VS Code properties. 34 | 35 | ### Visual Studio 36 | 37 | Visual Studio added dev container support in Visual Studio 2022 17.4 for C++ projects using CMake Presets. It is part of the Linux and embedded development with C++ workload, so make sure it is selected in your VS installation. Visual Studio manages the lifecycle of dev containers it uses as you work, but it treats them as remote targets in a similar way to other Linux or WSL targets. 38 | 39 | You may learn more in the [announcement blog post](https://devblogs.microsoft.com/cppblog/dev-containers-for-c-in-visual-studio/). 40 | 41 | ## Tools 42 | 43 | ### Dev Container CLI 44 | 45 | A dev container command line interface (CLI) that implements this specification. It is in development in the [devcontainers/cli](https://github.com/devcontainers/cli) repo. 46 | 47 | ### VS Code extension CLI 48 | 49 | VS Code has a [CLI](https://code.visualstudio.com/docs/remote/devcontainer-cli) which may be installed within the Dev Containers extension or through the command line. 50 | 51 | ### Cachix devenv 52 | 53 | Cachix's [devenv](https://devenv.sh/) supports automatically generating a `.devcontainer.json` file so you can use it with any Dev Container Spec supporting tool. See [devenv documentation](https://devenv.sh/integrations/codespaces-devcontainer/) for detais. 54 | 55 | ### Jetpack.io Devbox 56 | 57 | [Jetpack.io's VS Code extension](https://marketplace.visualstudio.com/items?itemName=jetpack-io.devbox) supports a **Generate Dev Container files** command so you can use Jetpack.io from Dev Container Spec supporting tools. 58 | 59 | ### Visual Studio Code Dev Containers 60 | 61 | The [**Visual Studio Code Dev Containers** extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) lets you use a container as a full-featured development environment. It allows you to open any folder inside (or mounted into) a container and take advantage of Visual Studio Code's full feature set. There is more information in the Dev Containers [documentation](https://code.visualstudio.com/docs/remote/containers). 62 | 63 | > **Tip:** If you've already built a container and connected to it, be sure to run **Dev Containers: Rebuild Container** from the Command Palette (`kbstyle(F1)`) to pick up any changes you make. 64 | 65 | #### Product specific properties 66 | 67 | Dev Containers implements the [VS Code](#visual-studio-code) specific properties. 68 | 69 | #### Product specific limitations 70 | 71 | Some properties may also have certain limitations in the Dev Containers extension. 72 | 73 | | Property or variable | Type | Description | 74 | |----------|------|-------------| 75 | | `workspaceMount` | string | Not yet supported when using Clone Repository in Container Volume. | 76 | | `workspaceFolder` | string | Not yet supported when using Clone Repository in Container Volume. | 77 | | `${localWorkspaceFolder}` | Any | Not yet supported when using Clone Repository in Container Volume. | 78 | | `${localWorkspaceFolderBasename}` | Any | Not yet supported when using Clone Repository in Container Volume. | 79 | 80 | ### GitHub Codespaces 81 | 82 | A [codespace](https://docs.github.com/en/codespaces/overview) is a development environment that's hosted in the cloud. Codespaces run on a variety of VM-based compute options hosted by GitHub.com, which you can configure from 2 core machines up to 32 core machines. You can connect to your codespaces from the browser or locally using Visual Studio Code. 83 | 84 | > **Tip:** If you've already built a codespace and connected to it, be sure to run **Codespaces: Rebuild Container** from the Command Palette (`kbstyle(F1)`) to pick up any changes you make. 85 | 86 | > **Tip:** Codespaces implements an auto `workspaceFolder` mount in **Docker Compose** scenarios. 87 | 88 | #### Product specific properties 89 | GitHub Codespaces works with a growing number of tools and, where applicable, their `devcontainer.json` properties. For example, connecting the codespaces web editor or VS Code enables the use of [VS Code properties](#visual-studio-code). 90 | 91 | If your codespaces project needs additional permissions for other repositories, you can configure this through the `repositories` and `permissions` properties. You may learn more about this in the [Codespaces documentation](https://docs.github.com/en/codespaces/managing-your-codespaces/managing-repository-access-for-your-codespaces). As with other tools, Codespaces specific properties are placed within a `codespaces` namespace inside the `customizations` property. 92 | 93 | ```jsonc 94 | "customizations": { 95 | // Configure properties specific to Codespaces. 96 | "codespaces": { 97 | "repositories": { 98 | "my_org/my_repo": { 99 | "permissions": { 100 | "issues": "write" 101 | } 102 | } 103 | } 104 | } 105 | } 106 | ``` 107 | 108 | You can customize which files are initially opened when the codespace is created: 109 | ```jsonc 110 | "customizations": { 111 | // Configure properties specific to Codespaces. 112 | "codespaces": { 113 | "openFiles": [ 114 | "README" 115 | "src/index.js" 116 | ] 117 | } 118 | } 119 | ``` 120 | 121 | The paths are relative to the root of the repository. They will be opened in order, with the first file activated. 122 | 123 | Codespaces will automatically perform some default setup when the `devcontainer.json` does not specify a `postCreateCommand`. This can be disabled with the `disableAutomaticConfiguration` setting: 124 | 125 | ```jsonc 126 | "customizations": { 127 | // Configure properties specific to Codespaces. 128 | "codespaces": { 129 | "disableAutomaticConfiguration": true 130 | } 131 | } 132 | ``` 133 | 134 | Note that currently codespaces reads these properties from `devcontainer.json`, not image metadata. 135 | 136 | #### Product specific limitations 137 | 138 | Some properties may apply differently to codespaces. 139 | 140 | | Property or variable | Type | Description | 141 | |----------|---------|----------------------| 142 | | `mounts` | array | Codespaces ignores "bind" mounts with the exception of the Docker socket. Volume mounts are still allowed.| 143 | | `forwardPorts` | array | Codespaces does not yet support the `"host:port"` variation of this property. | 144 | | `portsAttributes` | object | Codespaces does not yet support the `"host:port"` variation of this property.| 145 | | `shutdownAction` | enum | Does not apply to Codespaces. | 146 | | `${localEnv:VARIABLE_NAME}` | Any | For Codespaces, the host is in the cloud rather than your local machine.| 147 | | `customizations.codespaces` | object | Codespaces reads this property from devcontainer.json, not image metadata. | 148 | | `hostRequirements` | object | Codespaces reads this property from devcontainer.json, not image metadata. | 149 | -------------------------------------------------------------------------------- /docs/specs/devcontainer-templates.md: -------------------------------------------------------------------------------- 1 | # Dev Container Templates reference 2 | 3 | **Development Container Templates** are source files packaged together that encode configuration for a complete development environment. A Template can be used in a new or existing project, and a [supporting tool](https://containers.dev/supporting) will use the configuration from the Template to build a development container. 4 | 5 | The configuration is placed in [`.devcontainer/devcontainer.json`](/docs/specs/devcontainer-reference.md#devcontainerjson) which can also reference other files within the Template. A Template can also provide additional source files (e.g. boilerplate code or a [lifecycle script](https://containers.dev/implementors/json_reference/#lifecycle-scripts). 6 | 7 | Template metadata is captured by a `devcontainer-template.json` file in the root folder of the Template. 8 | 9 | ## Folder structure 10 | 11 | A single Template is a folder with at least a `devcontainer-template.json` and [`.devcontainer/devcontainer.json`](/docs/specs/devcontainer-reference.md#devcontainerjson). Additional files are permitted and are packaged along side the required files. 12 | 13 | ``` 14 | +-- template 15 | | +-- devcontainer-template.json 16 | | +-- .devcontainer 17 | | +-- devcontainer.json 18 | | +-- (other files) 19 | | +-- (other files) 20 | ``` 21 | 22 | ## devcontainer-template.json properties 23 | 24 | The `devcontainer-template.json` file defines information about the Template to be used by any [supporting tools](../docs/specs/supporting-tools.md#supporting-tools-and-services). 25 | 26 | The properties of the file are as follows: 27 | 28 | | Property | Type | Description | 29 | | :--- | :--- | :--- | 30 | | `id` | string | ID of the Template. The `id` should be unique in the context of the repository/published package where the Template exists and must match the name of the directory where the `devcontainer-template.json` resides. | 31 | | `version` | string | The semantic version of the Template. | 32 | | `name` | string | Name of the Template. | 33 | | `description` | string | Description of the Template. | 34 | | `documentationURL` | string | Url that points to the documentation of the Template. | 35 | | `licenseURL` | string | Url that points to the license of the Template. | 36 | | [`options`](#the-options-property) | object | A map of options that the supporting tools should use to populate different configuration options for the Template. | 37 | | `platforms` | array | Languages and platforms supported by the Template. | 38 | | `publisher` | string | Name of the publisher/maintainer of the Template. | 39 | | `keywords` | array | List of strings relevant to a user that would search for this Template. | 40 | | [`optionalPaths`](#the-optionalpaths-property) | array | An array of files or directories that tooling may consider "optional" when applying a Template. Directories are indicated with a trailing `/*` (e.g. `.github/*`). 41 | 42 | ### The `options` property 43 | 44 | The `options` property contains a map of option IDs and their related configuration settings. These `options` are used by the supporting tools to prompt the user to choose from different Template configuration options. The tools would replace the option ID with the selected value in all the files (within the sub-directory of the Template). This replacement would happen before dropping the `.devcontainer/devcontainer.json` and other files (within the sub-directory of the Template) required to containerize your project. See [option resolution](#option-resolution) for more details. For example: 45 | 46 | ```json 47 | { 48 | "options": { 49 | "optionId": { 50 | "type": "string", 51 | "description": "Description of the option", 52 | "proposals": ["value1", "value2"], 53 | "default": "value1" 54 | } 55 | } 56 | } 57 | ``` 58 | 59 | | Property | Type | Description | 60 | | :--- | :--- | :--- | 61 | | `optionId` | string | ID of the option used by the supporting tools to replace the selected value in the files within the sub-directory of the Template. | 62 | | `optionId.type` | string | Type of the option. Valid types are currently: `boolean`, `string` | 63 | | `optionId.description` | string | Description for the option. | 64 | | `optionId.proposals` | array | A list of suggested string values. Free-form values **are** allowed. Omit when using `optionId.enum`. | 65 | | `optionId.enum` | array | A strict list of allowed string values. Free-form values are **not** allowed. Omit when using `optionId.proposals`. | 66 | | `optionId.default` | string | Default value for the option. | 67 | 68 | > **Note:** The `options` must be unique for every `devcontainer-template.json` 69 | 70 | ### The `optionalPaths` property 71 | 72 | Before applying a Template, tooling must inspect the `optionalPaths` property of a Template and prompt the user on whether each file or folder should be included in the resulting output workspace folder. A path is relative to the root of the Template source directory. 73 | 74 | - For a single file, provide the full relative path (without any leading or trailing path delimiters). 75 | - For a directory, provide the full relative path with a trailing slash and asterisk (`/*`) appended to the path. The directory and its children will be recursively ignored. 76 | 77 | Examples are shown below: 78 | 79 | ```jsonc 80 | { 81 | "id": "cpp", 82 | "version": "3.0.0", 83 | "name": "C++", 84 | "description": "Develop C++ applications", 85 | "optionalPaths": [ 86 | "GETTING-STARTED.md", // Single file 87 | "example-project-1/MyProject.csproj", // Single file in nested directory 88 | ".github/*" // Entire recursive contents of directory 89 | ] 90 | } 91 | ``` 92 | 93 | ### Referencing a Template 94 | 95 | The `id` format (`//