Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@devcontainers/cli

Package Overview
Dependencies
Maintainers
3
Versions
99
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@devcontainers/cli - npm Package Compare versions

Comparing version 0.9.0 to 0.9.1

7

dist/spec-configuration/containerFeaturesConfiguration.d.ts

@@ -70,4 +70,3 @@ /// <reference types="node" />

type: 'file-path';
filePath: string;
isRelative: boolean;
resolvedFilePath: string;
}

@@ -134,3 +133,3 @@ export interface GithubSourceInformation extends BaseSourceInformation {

}, dstFolder: string, config: DevContainerConfig, getLocalFeaturesFolder: (d: string) => string): Promise<FeaturesConfig | undefined>;
export declare function getFeatureIdType(output: Log, env: NodeJS.ProcessEnv, id: string): Promise<{
export declare function getFeatureIdType(output: Log, env: NodeJS.ProcessEnv, userFeatureId: string): Promise<{
type: string;

@@ -142,3 +141,3 @@ manifest: undefined;

}>;
export declare function parseFeatureIdentifier(output: Log, env: NodeJS.ProcessEnv, userFeature: DevContainerFeature): Promise<FeatureSet | undefined>;
export declare function processFeatureIdentifier(output: Log, env: NodeJS.ProcessEnv, workspaceCwd: string, userFeature: DevContainerFeature): Promise<FeatureSet | undefined>;
export declare function getFeatureMainProperty(feature: Feature): "version" | undefined;

@@ -145,0 +144,0 @@ export declare function getFeatureMainValue(feature: Feature): string | boolean | undefined;

@@ -26,3 +26,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.getFeatureValueObject = exports.getFeatureMainValue = exports.getFeatureMainProperty = exports.parseFeatureIdentifier = exports.getFeatureIdType = exports.generateFeaturesConfig = exports.loadV1FeaturesJsonFromDisk = exports.loadFeaturesJson = exports.generateContainerEnvs = exports.getFeatureLayers = exports.getContainerFeaturesBaseDockerFile = exports.getSourceInfoString = exports.getContainerFeaturesFolder = exports.multiStageBuildExploration = exports.collapseFeaturesConfig = exports.DEVCONTAINER_FEATURE_FILE_NAME = exports.V1_DEVCONTAINER_FEATURES_FILE_NAME = void 0;
exports.getFeatureValueObject = exports.getFeatureMainValue = exports.getFeatureMainProperty = exports.processFeatureIdentifier = exports.getFeatureIdType = exports.generateFeaturesConfig = exports.loadV1FeaturesJsonFromDisk = exports.loadFeaturesJson = exports.generateContainerEnvs = exports.getFeatureLayers = exports.getContainerFeaturesBaseDockerFile = exports.getSourceInfoString = exports.getContainerFeaturesFolder = exports.multiStageBuildExploration = exports.collapseFeaturesConfig = exports.DEVCONTAINER_FEATURE_FILE_NAME = exports.V1_DEVCONTAINER_FEATURES_FILE_NAME = void 0;
const jsonc = __importStar(require("jsonc-parser"));

@@ -78,3 +78,3 @@ const path = __importStar(require("path"));

case 'file-path':
return srcInfo.filePath + '-' + getCounter();
return srcInfo.resolvedFilePath + '-' + getCounter();
case 'oci':

@@ -261,2 +261,4 @@ return `oci-${srcInfo.featureRef.resource}-${getCounter()}`;

const { output } = params;
const workspaceCwd = params.cwd;
output.write(`workspaceCwd: ${workspaceCwd}`, log_1.LogLevel.Trace);
const userFeatures = featuresToArray(config);

@@ -282,5 +284,6 @@ if (!userFeatures) {

output.write('--- Processing User Features ----', log_1.LogLevel.Trace);
featuresConfig = await processUserFeatures(params.output, params.env, userFeatures, featuresConfig);
featuresConfig = await processUserFeatures(params.output, params.env, workspaceCwd, userFeatures, featuresConfig);
output.write(JSON.stringify(featuresConfig, null, 4), log_1.LogLevel.Trace);
const ociCacheDir = await prepareOCICache(dstFolder);
// Fetch features and get version information
// Fetch features, stage into the appropriate build folder, and read the feature's devcontainer-feature.json
output.write('--- Fetching User Features ----', log_1.LogLevel.Trace);

@@ -319,5 +322,5 @@ await fetchFeatures(params, featuresConfig, locallyCachedFeatureSet, dstFolder, localFeaturesFolder, ociCacheDir);

// Creates one feature set per feature to aid in support of the previous structure.
async function processUserFeatures(output, env, userFeatures, featuresConfig) {
async function processUserFeatures(output, env, workspaceCwd, userFeatures, featuresConfig) {
for (const userFeature of userFeatures) {
const newFeatureSet = await parseFeatureIdentifier(output, env, userFeature);
const newFeatureSet = await processFeatureIdentifier(output, env, workspaceCwd, userFeature);
if (!newFeatureSet) {

@@ -330,3 +333,3 @@ throw new Error(`Failed to process feature ${userFeature.id}`);

}
async function getFeatureIdType(output, env, id) {
async function getFeatureIdType(output, env, userFeatureId) {
// See the specification for valid feature identifiers:

@@ -342,12 +345,12 @@ // > https://github.com/devcontainers/spec/blob/main/proposals/devcontainer-features.md#referencing-a-feature

// DEPRECATED: This is a legacy feature-set ID
if (!id.includes('/') && !id.includes('\\')) {
if (!userFeatureId.includes('/') && !userFeatureId.includes('\\')) {
return { type: 'local-cache', manifest: undefined };
}
// Direct tarball reference
if (id.startsWith('https://')) {
if (userFeatureId.startsWith('https://')) {
return { type: 'direct-tarball', manifest: undefined };
}
// Local feature on disk
const validPath = path.parse(id);
if (id.startsWith('./') || id.startsWith('../') || (validPath && path.isAbsolute(id))) {
// !! NOTE: The ability for paths outside the project file tree will soon be removed.
if (userFeatureId.startsWith('./') || userFeatureId.startsWith('../') || userFeatureId.startsWith('/')) {
return { type: 'file-path', manifest: undefined };

@@ -357,6 +360,6 @@ }

// DEPRECATED: This is a legacy feature-set ID
if (id.includes('@')) {
if (userFeatureId.includes('@')) {
return { type: 'github-repo', manifest: undefined };
}
const manifest = await (0, containerFeaturesOCI_1.fetchOCIFeatureManifestIfExists)(output, env, id);
const manifest = await (0, containerFeaturesOCI_1.fetchOCIFeatureManifestIfExists)(output, env, userFeatureId);
if (manifest) {

@@ -372,3 +375,5 @@ return { type: 'oci', manifest: manifest };

exports.getFeatureIdType = getFeatureIdType;
async function parseFeatureIdentifier(output, env, userFeature) {
// Strictly processes the user provided feature identifier to determine sourceInformation type.
// Returns a featureSet per feature.
async function processFeatureIdentifier(output, env, workspaceCwd, userFeature) {
output.write(`* Processing feature: ${userFeature.id}`);

@@ -419,12 +424,24 @@ const { type, manifest } = await getFeatureIdType(output, env, userFeature.id);

}
// If its a valid path
// If it matches the path syntax, it is a 'local' feature pointing to source code.
// Resolves the absolute path and ensures that the directory exists.
if (type === 'file-path') {
output.write(`Local disk feature.`);
const userFeaturePath = path.parse(userFeature.id);
//if (userFeaturePath && ((path.isAbsolute(userFeature.id) && existsSync(userFeature.id)) || !path.isAbsolute(userFeature.id))) {
const filePath = userFeature.id;
const id = userFeaturePath.name;
const isRelative = !path.isAbsolute(userFeature.id);
let resolvedFilePathToFeatureFolder = '';
if (path.isAbsolute(userFeature.id)) {
resolvedFilePathToFeatureFolder = userFeature.id;
}
else {
// A relative path to a feature directory is
// computed relative to the `--workspace-folder`
resolvedFilePathToFeatureFolder = path.join(workspaceCwd, userFeature.id);
}
output.write(`Resolved: ${userFeature.id} -> ${resolvedFilePathToFeatureFolder}`, log_1.LogLevel.Trace);
if (!resolvedFilePathToFeatureFolder || !(0, pfs_1.isLocalFolder)(resolvedFilePathToFeatureFolder)) {
output.write(`Local file path parse error. Resolved path to feature folder: ${resolvedFilePathToFeatureFolder}`, log_1.LogLevel.Error);
return undefined;
}
const id = path.basename(resolvedFilePathToFeatureFolder);
output.write(`Parsed feature id: ${id}`, log_1.LogLevel.Trace);
let feat = {
id: id,
id,
name: userFeature.id,

@@ -437,4 +454,3 @@ value: userFeature.options,

type: 'file-path',
filePath,
isRelative: isRelative
resolvedFilePath: resolvedFilePathToFeatureFolder,
},

@@ -513,3 +529,3 @@ features: [feat],

}
exports.parseFeatureIdentifier = parseFeatureIdentifier;
exports.processFeatureIdentifier = processFeatureIdentifier;
async function fetchFeatures(params, featuresConfig, localFeatures, dstFolder, localFeaturesFolder, ociCacheDir) {

@@ -543,3 +559,3 @@ var _a, _b;

}
if (!(await parseDevContainerFeature(output, featureSet, feature, featCachePath))) {
if (!(await applyFeatureConfigToFeature(output, featureSet, feature, featCachePath))) {
const err = `Failed to parse feature '${featureDebugId}'. Please check your devcontainer.json 'features' attribute.`;

@@ -554,3 +570,3 @@ throw new Error(err);

await (0, pfs_1.cpDirectoryLocal)(localFeaturesFolder, featCachePath);
if (!(await parseDevContainerFeature(output, featureSet, feature, featCachePath))) {
if (!(await applyFeatureConfigToFeature(output, featureSet, feature, featCachePath))) {
const err = `Failed to parse feature '${featureDebugId}'. Please check your devcontainer.json 'features' attribute.`;

@@ -563,9 +579,9 @@ throw new Error(err);

output.write(`Detected local file path`, log_1.LogLevel.Trace);
const executionPath = featureSet.sourceInformation.isRelative ? path.join(params.cwd, featureSet.sourceInformation.filePath) : featureSet.sourceInformation.filePath;
if (!(await parseDevContainerFeature(output, featureSet, feature, featCachePath))) {
await (0, pfs_1.mkdirpLocal)(featCachePath);
const executionPath = featureSet.sourceInformation.resolvedFilePath;
await (0, pfs_1.cpDirectoryLocal)(executionPath, featCachePath);
if (!(await applyFeatureConfigToFeature(output, featureSet, feature, featCachePath))) {
const err = `Failed to parse feature '${featureDebugId}'. Please check your devcontainer.json 'features' attribute.`;
throw new Error(err);
}
await (0, pfs_1.mkdirpLocal)(featCachePath);
await (0, pfs_1.cpDirectoryLocal)(executionPath, featCachePath);
continue;

@@ -605,3 +621,3 @@ }

output.write(`Succeeded fetching ${tarballUri}`, log_1.LogLevel.Trace);
if (!(await parseDevContainerFeature(output, featureSet, feature, featCachePath))) {
if (!(await applyFeatureConfigToFeature(output, featureSet, feature, featCachePath))) {
const err = `Failed to parse feature '${featureDebugId}'. Please check your devcontainer.json 'features' attribute.`;

@@ -665,10 +681,12 @@ throw new Error(err);

}
// Implements the latest ('internalVersion' = '2') parsing logic,
// Falls back to earlier implementation(s) if requirements not present.
//
// Returns a boolean indicating whether the feature was successfully parsed.
async function parseDevContainerFeature(output, featureSet, feature, featCachePath) {
// Reads the feature's 'devcontainer-feature.json` and applies any attributes to the in-memory Feature object.
// NOTE:
// Implements the latest ('internalVersion' = '2') parsing logic,
// Falls back to earlier implementation(s) if requirements not present.
// Returns a boolean indicating whether the feature was successfully parsed.
async function applyFeatureConfigToFeature(output, featureSet, feature, featCachePath) {
const innerJsonPath = path.join(featCachePath, exports.DEVCONTAINER_FEATURE_FILE_NAME);
if (!(await (0, pfs_1.isLocalFile)(innerJsonPath))) {
output.write(`Feature ${feature.id} is not a 'v2' feature. Attempting fallback to 'v1' implementation.`, log_1.LogLevel.Warning);
output.write(`For v2, expected devcontainer-feature.json at ${innerJsonPath}`, log_1.LogLevel.Trace);
return await parseDevContainerFeature_v1Impl(output, featureSet, feature, featCachePath);

@@ -675,0 +693,0 @@ }

{
"name": "@devcontainers/cli",
"description": "Dev Containers CLI",
"version": "0.9.0",
"version": "0.9.1",
"bin": {

@@ -34,5 +34,3 @@ "devcontainer": "devcontainer.js"

"test": "env TS_NODE_PROJECT=src/test/tsconfig.json mocha -r ts-node/register --exit src/test/*.test.ts",
"test-container-features": "env TS_NODE_PROJECT=src/test/tsconfig.json mocha -r ts-node/register --exit src/test/container-features/**/*.test.ts",
"test-container-features-offline": "env TS_NODE_PROJECT=src/test/tsconfig.json mocha -r ts-node/register --exit src/test/container-features/**/*.offline.test.ts",
"test-container-features-online": "env TS_NODE_PROJECT=src/test/tsconfig.json mocha -r ts-node/register --exit src/test/container-features/**/*.online.test.ts"
"test-container-features": "env TS_NODE_PROJECT=src/test/tsconfig.json mocha -r ts-node/register --exit src/test/container-features/*.test.ts"
},

@@ -39,0 +37,0 @@ "devDependencies": {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc