Example #1
0
        public async Task ExternalModuleNotInCacheShouldThrow()
        {
            var dispatcher = StrictMock.Of <IModuleDispatcher>();

            DiagnosticBuilder.ErrorBuilderDelegate?failureBuilder = null;
            const string UnqualifiedModuleRefStr = "example.azurecr.invalid/foo/bar:v3";
            const string ModuleRefStr            = "br:" + UnqualifiedModuleRefStr;

            var moduleReference = OciArtifactModuleReference.TryParse(null, UnqualifiedModuleRefStr, ConfigurationManager.GetBuiltInConfiguration(), out _) !;

            moduleReference.Should().NotBeNull();

            dispatcher.Setup(m => m.TryGetModuleReference(ModuleRefStr, It.IsAny <RootConfiguration>(), out failureBuilder)).Returns(moduleReference);
            dispatcher.Setup(m => m.GetModuleRestoreStatus(moduleReference, out failureBuilder)).Returns(ModuleRestoreStatus.Unknown);

            var resolver = StrictMock.Of <IFileResolver>();

            var handler = new BicepRegistryCacheRequestHandler(dispatcher.Object, resolver.Object, ConfigurationManager);

            var @params = new BicepRegistryCacheParams(ModuleRefStr);

            (await FluentActions
             .Awaiting(() => handler.Handle(@params, default))
             .Should()
             .ThrowAsync <InvalidOperationException>())
            .WithMessage($"The module '{ModuleRefStr}' has not yet been successfully restored.");
        }
        public void TryGetModuleReference_ValidAlias_ReplacesReferenceValue(string aliasName, string referenceValue, string fullyQualifiedReferenceValue, RootConfiguration configuration)
        {
            var reference = OciArtifactModuleReference.TryParse(aliasName, referenceValue, configuration, out var errorBuilder);

            reference.Should().NotBeNull();
            reference !.FullyQualifiedReference.Should().Be(fullyQualifiedReferenceValue);
        }
Example #3
0
        public async Task RestoredValidModuleShouldReturnSuccessfully()
        {
            var dispatcher = StrictMock.Of <IModuleDispatcher>();

            // needed for mocking out parameters
            DiagnosticBuilder.ErrorBuilderDelegate?nullBuilder        = null;
            DiagnosticBuilder.ErrorBuilderDelegate?readFailureBuilder = x => x.ErrorOccurredReadingFile("Mock file read failure.");
            string?fileContents = "mock file contents";

            const string UnqualifiedModuleRefStr = "example.azurecr.invalid/foo/bar:v3";
            const string ModuleRefStr            = "br:" + UnqualifiedModuleRefStr;

            var moduleReference = OciArtifactModuleReference.TryParse(null, UnqualifiedModuleRefStr, ConfigurationManager.GetBuiltInConfiguration(), out _) !;

            moduleReference.Should().NotBeNull();

            var fileUri = new Uri("file:///main.bicep");

            dispatcher.Setup(m => m.TryGetModuleReference(ModuleRefStr, It.IsAny <RootConfiguration>(), out nullBuilder)).Returns(moduleReference);
            dispatcher.Setup(m => m.GetModuleRestoreStatus(moduleReference, out nullBuilder)).Returns(ModuleRestoreStatus.Succeeded);
            dispatcher.Setup(m => m.TryGetLocalModuleEntryPointUri(null, moduleReference, out nullBuilder)).Returns(fileUri);

            var resolver = StrictMock.Of <IFileResolver>();

            resolver.Setup(m => m.TryRead(fileUri, out fileContents, out nullBuilder)).Returns(true);

            var handler = new BicepRegistryCacheRequestHandler(dispatcher.Object, resolver.Object, ConfigurationManager);

            var @params  = new BicepRegistryCacheParams(ModuleRefStr);
            var response = await handler.Handle(@params, default);

            response.Should().NotBeNull();
            response.Content.Should().Be(fileContents);
        }
Example #4
0
        public async Task ExternalModuleFailedEntryPointShouldThrow()
        {
            var dispatcher = StrictMock.Of <IModuleDispatcher>();

            DiagnosticBuilder.ErrorBuilderDelegate?failureBuilder = null;
            const string UnqualifiedModuleRefStr = "example.azurecr.invalid/foo/bar:v3";
            const string ModuleRefStr            = "br:" + UnqualifiedModuleRefStr;

            var configuration   = ConfigurationManager.GetBuiltInConfiguration();
            var moduleReference = OciArtifactModuleReference.TryParse(null, UnqualifiedModuleRefStr, configuration, out _) !;

            moduleReference.Should().NotBeNull();

            dispatcher.Setup(m => m.TryGetModuleReference(ModuleRefStr, It.IsAny <RootConfiguration>(), out failureBuilder)).Returns(moduleReference);
            dispatcher.Setup(m => m.GetModuleRestoreStatus(moduleReference, configuration, out failureBuilder)).Returns(ModuleRestoreStatus.Succeeded);
            dispatcher.Setup(m => m.TryGetLocalModuleEntryPointUri(null, moduleReference, configuration, out failureBuilder)).Returns <Uri?>(null);

            var resolver = StrictMock.Of <IFileResolver>();

            var handler = new BicepRegistryCacheRequestHandler(dispatcher.Object, resolver.Object, ConfigurationManager);

            var @params = new BicepRegistryCacheParams("/main.bicep", ModuleRefStr);

            (await FluentActions
             .Awaiting(() => handler.Handle(@params, default))
             .Should()
             .ThrowAsync <InvalidOperationException>())
            .WithMessage($"Unable to obtain the entry point URI for module '{ModuleRefStr}'.");
        }
        private static OciArtifactModuleReference Parse(string package)
        {
            var parsed = OciArtifactModuleReference.TryParse(null, package, BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled, out var failureBuilder);

            failureBuilder !.Should().BeNull();
            parsed.Should().NotBeNull();
            return(parsed !);
        }
        public void TryParse_InvalidAliasName_ReturnsNullAndSetsErrorDiagnostic(string aliasName)
        {
            var reference = OciArtifactModuleReference.TryParse(aliasName, "", BicepTestConstants.BuiltInConfiguration, out var errorBuilder);

            reference.Should().BeNull();
            errorBuilder !.Should().HaveCode("BCP211");
            errorBuilder !.Should().HaveMessage($"The module alias name \"{aliasName}\" is invalid. Valid characters are alphanumeric, \"_\", or \"-\".");
        }
        public void TryParse_InvalidAlias_ReturnsNullAndSetsError(string aliasName, string referenceValue, RootConfiguration configuration, string expectedCode, string expectedMessage)
        {
            var reference = OciArtifactModuleReference.TryParse(aliasName, referenceValue, configuration, out var errorBuilder);

            reference.Should().BeNull();
            ((object?)errorBuilder).Should().NotBeNull();
            errorBuilder !.Should().HaveCode(expectedCode);
            errorBuilder !.Should().HaveMessage(expectedMessage);
        }
        public void TryParse_AliasNotInConfiguration_ReturnsNullAndSetsError(string aliasName, string referenceValue, string?configurationPath, string expectedCode, string expectedMessage)
        {
            var configuration = BicepTestConstants.CreateMockConfiguration(configurationPath: configurationPath);

            var reference = OciArtifactModuleReference.TryParse(aliasName, referenceValue, configuration, out var errorBuilder);

            reference.Should().BeNull();
            ((object?)errorBuilder).Should().NotBeNull();
            errorBuilder !.Should().HaveCode(expectedCode);
            errorBuilder !.Should().HaveMessage(expectedMessage);
        }
        public void InvalidReferencesShouldProduceExpectedError(string value, string expectedCode, string expectedError)
        {
            OciArtifactModuleReference.TryParse(null, value, BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled, out var failureBuilder).Should().BeNull();
            failureBuilder !.Should().NotBeNull();

            using (new AssertionScope())
            {
                failureBuilder !.Should().HaveCode(expectedCode);
                failureBuilder !.Should().HaveMessage(expectedError);
            }
        }
Example #10
0
        public async Task FailureToReadEntryPointShouldThrow()
        {
            var dispatcher = StrictMock.Of <IModuleDispatcher>();

            // needed for mocking out parameters
            DiagnosticBuilder.ErrorBuilderDelegate?nullBuilder        = null;
            DiagnosticBuilder.ErrorBuilderDelegate?readFailureBuilder = x => x.ErrorOccurredReadingFile("Mock file read failure.");
            string?fileContents = null;

            const string UnqualifiedModuleRefStr = "example.azurecr.invalid/foo/bar:v3";
            const string ModuleRefStr            = "br:" + UnqualifiedModuleRefStr;

            var configuration   = ConfigurationManager.GetBuiltInConfiguration();
            var moduleReference = OciArtifactModuleReference.TryParse(null, UnqualifiedModuleRefStr, configuration, out _) !;

            moduleReference.Should().NotBeNull();

            var fileUri = new Uri("file:///main.bicep");

            dispatcher.Setup(m => m.TryGetModuleReference(ModuleRefStr, It.IsAny <RootConfiguration>(), out nullBuilder)).Returns(moduleReference);
            dispatcher.Setup(m => m.GetModuleRestoreStatus(moduleReference, configuration, out nullBuilder)).Returns(ModuleRestoreStatus.Succeeded);
            dispatcher.Setup(m => m.TryGetLocalModuleEntryPointUri(null, moduleReference, configuration, out nullBuilder)).Returns(fileUri);

            var resolver = StrictMock.Of <IFileResolver>();

            resolver.Setup(m => m.TryRead(fileUri, out fileContents, out readFailureBuilder)).Returns(false);

            var handler = new BicepRegistryCacheRequestHandler(dispatcher.Object, resolver.Object, ConfigurationManager);

            var @params = new BicepRegistryCacheParams(fileUri.AbsolutePath, ModuleRefStr);

            (await FluentActions
             .Awaiting(() => handler.Handle(@params, default))
             .Should()
             .ThrowAsync <InvalidOperationException>())
            .WithMessage($"Unable to read file 'file:///main.bicep'. An error occurred reading file. Mock file read failure.");
        }
Example #11
0
        private static async Task <(OciManifest, Stream, string)> DownloadManifestAsync(OciArtifactModuleReference moduleReference, BicepRegistryBlobClient client)
        {
            Response <DownloadManifestResult> manifestResponse;

            try
            {
                manifestResponse = await client.DownloadManifestAsync(moduleReference.Tag, new DownloadManifestOptions(ContentType.ApplicationVndOciImageManifestV1Json));
            }
            catch (RequestFailedException exception) when(exception.Status == 404)
            {
                // manifest does not exist
                throw new OciModuleRegistryException("The module does not exist in the registry.", exception);
            }

            ValidateManifestResponse(manifestResponse);

            // the SDK doesn't expose all the manifest properties we need
            // so we need to deserialize the manifest ourselves to get everything
            var stream = manifestResponse.Value.Content;

            stream.Position = 0;
            var deserialized = DeserializeManifest(stream);

            stream.Position = 0;

            return(deserialized, stream, manifestResponse.Value.Digest);
        }
Example #12
0
 private BicepRegistryBlobClient CreateBlobClient(Configuration.RootConfiguration configuration, OciArtifactModuleReference moduleReference) => this.clientFactory.CreateBlobClient(configuration, GetRegistryUri(moduleReference), moduleReference.Repository);
Example #13
0
 private static Uri GetRegistryUri(OciArtifactModuleReference moduleReference) => new Uri($"https://{moduleReference.Registry}");
Example #14
0
        public async Task PushArtifactAsync(Configuration.RootConfiguration configuration, OciArtifactModuleReference moduleReference, StreamDescriptor config, params StreamDescriptor[] layers)
        {
            // TODO: Add similar exception handling as in the pull* method

            // TODO: How do we choose this? Does it ever change?
            var algorithmIdentifier = DescriptorFactory.AlgorithmIdentifierSha256;

            var blobClient = this.CreateBlobClient(configuration, moduleReference);

            config.ResetStream();
            var configDescriptor = DescriptorFactory.CreateDescriptor(algorithmIdentifier, config);

            config.ResetStream();
            var configUploadResult = await blobClient.UploadBlobAsync(config.Stream);

            var layerDescriptors = new List <OciDescriptor>(layers.Length);

            foreach (var layer in layers)
            {
                layer.ResetStream();
                var layerDescriptor = DescriptorFactory.CreateDescriptor(algorithmIdentifier, layer);
                layerDescriptors.Add(layerDescriptor);

                layer.ResetStream();
                var layerUploadResult = await blobClient.UploadBlobAsync(layer.Stream);
            }

            var manifest = new OciManifest(2, configDescriptor, layerDescriptors);

            using var manifestStream = new MemoryStream();
            OciSerialization.Serialize(manifestStream, manifest);

            manifestStream.Position = 0;
            // BUG: the client closes the stream :(
            var manifestUploadResult = await blobClient.UploadManifestAsync(manifestStream, new UploadManifestOptions(ContentType.ApplicationVndOciImageManifestV1Json, moduleReference.Tag));
        }
Example #15
0
        public async Task <OciArtifactResult> PullArtifactAsync(Configuration.RootConfiguration configuration, OciArtifactModuleReference moduleReference)
        {
            var client = this.CreateBlobClient(configuration, moduleReference);

            var(manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client);

            var moduleStream = await ProcessManifest(client, manifest);

            return(new OciArtifactResult(manifestDigest, manifest, manifestStream, moduleStream));
        }
Example #16
0
        public async Task <OciArtifactResult> PullArtifactAsync(RootConfiguration configuration, OciArtifactModuleReference moduleReference)
        {
            var client = this.CreateBlobClient(configuration, moduleReference);

            OciManifest manifest;
            Stream      manifestStream;
            string      manifestDigest;

            try
            {
                Trace.WriteLine($"Authenticated attempt to pull artifact for module {moduleReference.FullyQualifiedReference}.");
                // Try authenticated client first.
                (manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client);
            }
            catch (RequestFailedException exception) when(exception.Status == 401 || exception.Status == 403)
            {
                Trace.WriteLine($"Authenticated attempt to pull artifact for module {moduleReference.FullyQualifiedReference} failed, received code {exception.Status}. Fallback to anonymous pull.");
                // Fall back to anonymous client.
                client = this.CreateBlobClient(configuration, moduleReference, anonymousAccess: true);
                (manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client);
            }

            var moduleStream = await ProcessManifest(client, manifest);

            return(new OciArtifactResult(manifestDigest, manifest, manifestStream, moduleStream));
        }
        public async Task <OciArtifactResult> PullArtifactAsync(RootConfiguration configuration, OciArtifactModuleReference moduleReference)
        {
            var client = this.CreateBlobClient(configuration, moduleReference);

            OciManifest manifest;
            Stream      manifestStream;
            string      manifestDigest;

            try
            {
                // Try authenticated client first.
                (manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client);
            }
            catch (RequestFailedException exception) when(exception.Status == 401)
            {
                // Fall back to anonymous client.
                client = this.CreateBlobClient(configuration, moduleReference, anonymousAccess: true);
                (manifest, manifestStream, manifestDigest) = await DownloadManifestAsync(moduleReference, client);
            }

            var moduleStream = await ProcessManifest(client, manifest);

            return(new OciArtifactResult(manifestDigest, manifest, manifestStream, moduleStream));
        }