Skip to content

Commit 0a4782d

Browse files
Block secure outputs in local deploy (#17235)
## Description Block secure outputs in local deploy Discovered when trying to test https://github.com/anthony-c-martin/samples/tree/main/bicep/local-deploy-github-oidc. ## Checklist - [x] I have read and adhere to the [contribution guide](https://github.com/Azure/bicep/blob/main/CONTRIBUTING.md).
1 parent 3c8ba66 commit 0a4782d

File tree

11 files changed

+202
-72
lines changed

11 files changed

+202
-72
lines changed

.vscode/launch.json

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
],
1313
"env": {
1414
"BICEP_TRACING_ENABLED": "true",
15-
15+
"BICEP_TRACING_VERBOSITY": "basic",
16+
"BICEP_EXTENSION_TRACING_ENABLED": "false",
1617
// Defaulting to "verbose" when debugging so that new telemetry IDs during development aren't accidentally sent and created before they're finalized
1718
"DEBUGTELEMETRY": "v", // "" or "0" or "false": send telemetry as normal; "1": debug mode (no telemetry sent); "verbose": telemetry in console, don't send (from microsoft/vscode-azext-utils)
1819
},
@@ -32,25 +33,10 @@
3233
"build",
3334
"${file}"
3435
],
35-
"env": {
36-
"BICEP_TRACING_ENABLED": "true"
37-
},
38-
"cwd": "${workspaceFolder}/src/Bicep.Cli",
39-
"console": "internalConsole",
40-
"stopAtEntry": false
41-
},
42-
{
43-
"name": "CLI-Test",
44-
"type": "coreclr",
45-
"request": "launch",
46-
"preLaunchTask": "Build CLI",
47-
"program": "${workspaceFolder}/src/Bicep.Cli/bin/Debug/net8.0/bicep",
48-
"args": [
49-
"test",
50-
"${file}"
51-
],
5236
"env": {
5337
"BICEP_TRACING_ENABLED": "true",
38+
"BICEP_TRACING_VERBOSITY": "basic",
39+
"BICEP_EXTENSION_TRACING_ENABLED": "false",
5440
},
5541
"cwd": "${workspaceFolder}/src/Bicep.Cli",
5642
"console": "internalConsole",
@@ -113,4 +99,4 @@
11399
"cwd": "${workspaceFolder}/src/vscode-bicep-ui/apps/deploy-pane"
114100
},
115101
]
116-
}
102+
}

docs/experimental/local-deploy.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,26 @@ Here's an example bicepconfig.json you can use to share your extension with othe
9595
9696
* You will need to update `extensions.http`: the key (`http`) should be the name of your extension, and the value (`br:bicepextdemo.azurecr.io/extensions/http:0.1.1`) should be the OCI reference path (or relative local file system path if building locally).
9797
98+
### Troubleshooting
99+
100+
The following environment variables can be used to enable detailed logging for extension binary stdout, stderr and gRPC requests & responses. This can be useful for extension authors to troubleshoot problems invoking extensions.
101+
102+
Note that this can include sensitive data, and should only be used for local debugging.
103+
104+
1. (Mac/Linux) Run the following:
105+
```sh
106+
export BICEP_TRACING_ENABLED=true
107+
export BICEP_EXTENSION_TRACING_ENABLED=true
108+
```
109+
1. (Windows) Run the following in a PowerShell window:
110+
```powershell
111+
$env:BICEP_TRACING_ENABLED = $true
112+
$env:BICEP_EXTENSION_TRACING_ENABLED = $true
113+
```
98114
99115
## Limitations
100116
1. Code signing for the proof-of-concept extensions has not been implemented, meaning you may run into errors running the samples on a Mac.
117+
1. Secure outputs are not currently supported.
101118
102119
## Raising bugs or feature requests
103120
Please raise bug reports or feature requests under [Bicep Issues](https://github.com/Azure/bicep/issues) as usual.

src/Bicep.Cli/Commands/LocalDeployCommand.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,14 @@ parameters.Parameters is not { } parametersString ||
6363
return 1;
6464
}
6565

66-
await using var extensionHostManager = dispatcherFactory.Create();
67-
await extensionHostManager.InitializeExtensions(compilation);
68-
var result = await extensionHostManager.Deploy(templateString, parametersString, cancellationToken);
66+
67+
// this using block is intentional to ensure that the dispatcher completes running before we write the summary
68+
LocalDeploymentResult result;
69+
await using (var dispatcher = dispatcherFactory.Create())
70+
{
71+
await dispatcher.InitializeExtensions(compilation);
72+
result = await dispatcher.Deploy(templateString, parametersString, cancellationToken);
73+
}
6974

7075
await WriteSummary(result);
7176
return result.Deployment.Properties.ProvisioningState == ProvisioningState.Succeeded ? 0 : 1;

src/Bicep.Core.IntegrationTests/ScenarioTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7354,4 +7354,29 @@ param shouldDeploy bool
73547354
("BCP420", DiagnosticLevel.Error, "The scope could not be resolved at compile time because the supplied expression is ambiguous or too complex. Scoping expressions must be reducible to a specific kind of scope without knowledge of parameter values."),
73557355
});
73567356
}
7357+
7358+
[TestMethod]
7359+
public void Local_deploy_cannot_be_used_with_secure_outputs()
7360+
{
7361+
var result = CompilationHelper.Compile(Services.WithFeatureOverrides(new(LocalDeployEnabled: true)), ("main.bicep", """
7362+
targetScope = 'local'
7363+
7364+
module mod 'mod.bicep' = {
7365+
scope: resourceGroup('00000000-0000-0000-0000-000000000000', 'foo')
7366+
params: {
7367+
secret: 'blah'
7368+
}
7369+
}
7370+
"""), ("mod.bicep", """
7371+
@secure()
7372+
param secret string
7373+
7374+
@secure()
7375+
output secret string = secret
7376+
"""));
7377+
7378+
result.ExcludingLinterDiagnostics().Should().HaveDiagnostics([
7379+
("BCP421", DiagnosticLevel.Error, """Module "mod" contains one or more secure outputs, which are not supported with "targetScope" set to "local"."""),
7380+
]);
7381+
}
73577382
}

src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1911,6 +1911,10 @@ public Diagnostic InvalidReservedImplicitExtensionNamespace(string name) => Core
19111911
public Diagnostic ScopeKindUnresolvableAtCompileTime() => CoreError(
19121912
"BCP420",
19131913
"The scope could not be resolved at compile time because the supplied expression is ambiguous or too complex. Scoping expressions must be reducible to a specific kind of scope without knowledge of parameter values.");
1914+
1915+
public Diagnostic SecureOutputsNotSupportedWithLocalDeploy(string moduleName) => CoreError(
1916+
"BCP421",
1917+
$"""Module "{moduleName}" contains one or more secure outputs, which are not supported with "{LanguageConstants.TargetScopeKeyword}" set to "{LanguageConstants.TargetScopeTypeLocal}".""");
19141918
}
19151919

19161920
public static DiagnosticBuilderInternal ForPosition(TextSpan span)

src/Bicep.Core/Emit/EmitLimitationCalculator.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public static EmitLimitationInfo Calculate(SemanticModel model)
5555
BlockNamesDistinguishedOnlyByCase(model, diagnostics);
5656
BlockResourceDerivedTypesThatDoNotDereferenceProperties(model, diagnostics);
5757
BlockSpreadInUnsupportedLocations(model, diagnostics);
58+
BlockSecureOutputsWithLocalDeploy(model, diagnostics);
5859
BlockExtendsWithoutFeatureFlagEnabled(model, diagnostics);
5960

6061
var paramAssignments = CalculateParameterAssignments(model, diagnostics);
@@ -974,5 +975,22 @@ IEnumerable<ObjectSyntax> getObjectSyntaxesToBlock()
974975
}
975976
}
976977
}
978+
979+
private static void BlockSecureOutputsWithLocalDeploy(SemanticModel model, IDiagnosticWriter diagnostics)
980+
{
981+
if (model.TargetScope != ResourceScope.Local)
982+
{
983+
return;
984+
}
985+
986+
foreach (var module in model.Root.ModuleDeclarations)
987+
{
988+
if (module.TryGetSemanticModel().TryUnwrap() is { } moduleModel &&
989+
moduleModel.Outputs.Any(output => output.IsSecure))
990+
{
991+
diagnostics.Write(DiagnosticBuilder.ForPosition(module.NameSource).SecureOutputsNotSupportedWithLocalDeploy(module.Name));
992+
}
993+
}
994+
}
977995
}
978996
}

src/Bicep.Core/Features/FeatureProvider.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,13 @@ public FeatureProvider(RootConfiguration configuration, IFileExplorer fileExplor
3636

3737
public bool AssertsEnabled => configuration.ExperimentalFeaturesEnabled.Assertions;
3838

39-
public static bool TracingEnabled => ReadBooleanEnvVar("BICEP_TRACING_ENABLED", defaultValue: false);
39+
public static readonly bool TracingEnabled = ReadBooleanEnvVar("BICEP_TRACING_ENABLED", defaultValue: false);
4040

41-
public static TraceVerbosity TracingVerbosity => ReadEnumEnvVar("BICEP_TRACING_VERBOSITY", TraceVerbosity.Basic);
41+
public static readonly bool ExtensionTracingEnabled = ReadBooleanEnvVar("BICEP_EXTENSION_TRACING_ENABLED", defaultValue: false);
42+
43+
public static readonly TraceVerbosity TracingVerbosity = ReadEnumEnvVar("BICEP_TRACING_VERBOSITY", TraceVerbosity.Basic);
44+
45+
public static bool HasTracingVerbosity(TraceVerbosity verbosity) => TracingVerbosity >= verbosity;
4246

4347
public bool WaitAndRetryEnabled => configuration.ExperimentalFeaturesEnabled.WaitAndRetry;
4448

src/Bicep.Core/Features/TraceVerbosity.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33

44
namespace Bicep.Core.Features
55
{
6+
/// <remarks>
7+
/// The enum values must be in order of increasing verbosity, as they're used to determine the level of detail in tracing output.
8+
/// See <see cref="FeatureProvider.HasTracingVerbosity"/> for more details on how this is used.
9+
/// </remarks>
610
public enum TraceVerbosity
711
{
8-
Basic,
9-
Full
12+
Basic = 0,
13+
Full = 1,
1014
}
1115
}

0 commit comments

Comments
 (0)