Skip to content

Commit b44c0f2

Browse files
committed
Secrets and trim native binaries
- Fix #7 Added context menus for add/edit/delete secrets at the repo level. - Removed arm/x86 binaries for lib2git
1 parent 6df53cf commit b44c0f2

File tree

9 files changed

+202
-10
lines changed

9 files changed

+202
-10
lines changed

src/GitHubActionsVS.csproj

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,20 @@
6565
<Compile Include="ToolWindows\MessagePayload.cs" />
6666
<Compile Include="ToolWindows\MessageCommand.cs" />
6767
<Compile Include="ToolWindows\ToolWindowMessenger.cs" />
68+
<Compile Include="UserControls\AddEditSecret.xaml.cs">
69+
<DependentUpon>AddEditSecret.xaml</DependentUpon>
70+
</Compile>
6871
<Compile Include="VSCommandTable.cs">
6972
<AutoGen>True</AutoGen>
7073
<DesignTime>True</DesignTime>
7174
<DependentUpon>VSCommandTable.vsct</DependentUpon>
7275
</Compile>
7376
</ItemGroup>
7477
<ItemGroup>
78+
<Content Include="libsodium.dll">
79+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
80+
<IncludeInVSIX>true</IncludeInVSIX>
81+
</Content>
7582
<Resource Include="Resources\codicon.ttf" />
7683
<Content Include="LICENSE">
7784
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
@@ -81,18 +88,10 @@
8188
<SubType>Designer</SubType>
8289
<Generator>VsixManifestGenerator</Generator>
8390
</None>
84-
<Content Include="lib\win32\arm64\git2-e632535.dll">
85-
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
86-
<IncludeInVSIX>true</IncludeInVSIX>
87-
</Content>
8891
<Content Include="lib\win32\x64\git2-e632535.dll">
8992
<IncludeInVSIX>true</IncludeInVSIX>
9093
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
9194
</Content>
92-
<Content Include="lib\win32\x86\git2-e632535.dll">
93-
<IncludeInVSIX>true</IncludeInVSIX>
94-
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
95-
</Content>
9695
<Content Include="Resources\Icon.png">
9796
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
9897
<IncludeInVSIX>true</IncludeInVSIX>
@@ -111,6 +110,10 @@
111110
<SubType>Designer</SubType>
112111
<Generator>MSBuild:Compile</Generator>
113112
</Page>
113+
<Page Include="UserControls\AddEditSecret.xaml">
114+
<SubType>Designer</SubType>
115+
<Generator>MSBuild:Compile</Generator>
116+
</Page>
114117
</ItemGroup>
115118
<ItemGroup>
116119
<Reference Include="System" />
@@ -150,6 +153,9 @@
150153
<PackageReference Include="Octokit">
151154
<Version>7.0.1</Version>
152155
</PackageReference>
156+
<PackageReference Include="Sodium.Core">
157+
<Version>1.3.3</Version>
158+
</PackageReference>
153159
</ItemGroup>
154160
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
155161
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />

src/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
[assembly: ComVisible(false)]
1515

1616
[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\LibGit2Sharp.dll")]
17+
[assembly: ProvideCodeBase(CodeBase = @"$PackageFolder$\Sodium.Core.dll")]
1718

1819
namespace System.Runtime.CompilerServices;
1920
public class IsExternalInit { }

src/ToolWindows/GHActionsToolWindow.xaml

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,29 @@
5656
<Expander Header="Settings">
5757
<TreeView BorderThickness="0">
5858
<TreeViewItem Header="Secrets" HeaderTemplate="{DynamicResource SecretsHeaderTemplate}">
59-
<TreeViewItem Header="Repository Secrets" x:Name="tvSecrets"/>
59+
<TreeViewItem x:Name="tvSecrets">
60+
<TreeViewItem.Header>
61+
<TextBlock Text="Repository Secrets">
62+
<TextBlock.ContextMenu>
63+
<ContextMenu>
64+
<MenuItem Header="Add Secret" Click="AddSecret_Click" />
65+
</ContextMenu>
66+
</TextBlock.ContextMenu>
67+
</TextBlock>
68+
</TreeViewItem.Header>
69+
<TreeViewItem.ItemTemplate>
70+
<DataTemplate>
71+
<TextBlock Text="{Binding}">
72+
<TextBlock.ContextMenu>
73+
<ContextMenu>
74+
<MenuItem Header="Edit Secret" Click="EditSecret_Click" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}}" />
75+
<MenuItem Header="Delete Secret" Click="DeleteSecret_Click" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}}" />
76+
</ContextMenu>
77+
</TextBlock.ContextMenu>
78+
</TextBlock>
79+
</DataTemplate>
80+
</TreeViewItem.ItemTemplate>
81+
</TreeViewItem>
6082
</TreeViewItem>
6183
</TreeView>
6284
</Expander>

src/ToolWindows/GHActionsToolWindow.xaml.cs

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
using System.Windows;
88
using System.Windows.Controls;
99
using System.Windows.Input;
10+
using GitHubActionsVS.UserControls;
11+
using Application = System.Windows.Application;
12+
using System.Windows.Media;
13+
using MessageBox = Community.VisualStudio.Toolkit.MessageBox;
1014

1115
namespace GitHubActionsVS;
1216

@@ -65,6 +69,12 @@ public async Task GetRepoInfoAsync()
6569

6670
// find the git folder
6771
var solution = await VS.Solutions.GetCurrentSolutionAsync();
72+
if (solution is null)
73+
{
74+
Debug.WriteLine("No solution found");
75+
ShowInfoMessage("No project or solution loaded");
76+
return;
77+
}
6878
var projectPath = solution?.FullPath;
6979

7080
_repoInfo.FindGitFolder(projectPath, out string gitPath);
@@ -135,7 +145,7 @@ private async Task LoadDataAsync()
135145
if (runs.TotalCount > 0)
136146
{
137147
// creating simplified model of the GH info for the treeview
138-
148+
139149
// iterate throught the runs
140150
foreach (var run in runs.WorkflowRuns)
141151
{
@@ -257,5 +267,87 @@ private void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)
257267
parent.RaiseEvent(eventArg);
258268
}
259269
}
270+
271+
private async void AddSecret_Click(object sender, RoutedEventArgs e)
272+
{
273+
await UpsertRepositorySecret(string.Empty);
274+
}
275+
276+
private async void EditSecret_Click(object sender, RoutedEventArgs e)
277+
{
278+
MenuItem menuItem = (MenuItem)sender;
279+
TextBlock tvi = GetParentTreeViewItem(menuItem);
280+
if (tvi is not null)
281+
{
282+
string header = tvi.Text.ToString();
283+
string secretName = header.Substring(0, header.IndexOf(" ("));
284+
await UpsertRepositorySecret(secretName);
285+
}
286+
}
287+
288+
private TextBlock GetParentTreeViewItem(MenuItem menuItem)
289+
{
290+
var contextMenu = menuItem.CommandParameter as ContextMenu;
291+
if (contextMenu is not null)
292+
{
293+
var treeViewItem = contextMenu.PlacementTarget as TextBlock;
294+
if (treeViewItem is not null)
295+
{
296+
return treeViewItem;
297+
}
298+
}
299+
return null;
300+
}
301+
302+
private async void DeleteSecret_Click(object sender, RoutedEventArgs e)
303+
{
304+
MenuItem menuItem = (MenuItem)sender;
305+
TextBlock tvi = GetParentTreeViewItem(menuItem);
306+
307+
if (tvi is not null)
308+
{
309+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
310+
// confirm the delete first
311+
int result = VsShellUtilities.ShowMessageBox(ServiceProvider.GlobalProvider, "Are you sure you want to delete this secret?", "Confirm Delete", Microsoft.VisualStudio.Shell.Interop.OLEMSGICON.OLEMSGICON_QUERY, Microsoft.VisualStudio.Shell.Interop.OLEMSGBUTTON.OLEMSGBUTTON_YESNOCANCEL, Microsoft.VisualStudio.Shell.Interop.OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_THIRD);
312+
313+
var confirmResult = (MessageBoxResult)result;
314+
315+
if (confirmResult == MessageBoxResult.Yes)
316+
{
317+
string header = tvi.Text.ToString();
318+
string secretName = header.Substring(0, header.IndexOf(" ("));
319+
320+
GitHubClient client = GetGitHubClient();
321+
await client.Repository.Actions.Secrets.Delete(_repoInfo.RepoOwner, _repoInfo.RepoName, secretName);
322+
await RefreshSecretsAsync(client);
323+
}
324+
}
325+
}
326+
327+
private async Task UpsertRepositorySecret(string secretName)
328+
{
329+
AddEditSecret addEditSecret = new AddEditSecret(secretName)
330+
{
331+
Owner = Application.Current.MainWindow
332+
};
333+
bool? result = addEditSecret.ShowDialog();
334+
if (result == true)
335+
{
336+
GitHubClient client = GetGitHubClient();
337+
var pubKey = await client.Repository.Actions.Secrets.GetPublicKey(_repoInfo.RepoOwner, _repoInfo.RepoName);
338+
339+
UpsertRepositorySecret encryptedSecret = new UpsertRepositorySecret();
340+
if (pubKey != null)
341+
{
342+
var bytes = System.Text.Encoding.UTF8.GetBytes(addEditSecret.SecretValue);
343+
var key = Convert.FromBase64String(pubKey.Key);
344+
var sealedKeyBox = Sodium.SealedPublicKeyBox.Create(bytes, key);
345+
encryptedSecret.KeyId = pubKey.KeyId;
346+
encryptedSecret.EncryptedValue = Convert.ToBase64String(sealedKeyBox);
347+
_ = await client.Repository.Actions.Secrets.CreateOrUpdate(_repoInfo.RepoOwner, _repoInfo.RepoName, addEditSecret.SecretName, encryptedSecret);
348+
}
349+
await RefreshSecretsAsync(client);
350+
}
351+
}
260352
}
261353

src/UserControls/AddEditSecret.xaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Window x:Class="GitHubActionsVS.UserControls.AddEditSecret"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:local="clr-namespace:GitHubActionsVS.Helpers"
5+
Title="Add/Edit Secret" Height="220" Width="500" ResizeMode="NoResize" ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
6+
xmlns:toolkit="clr-namespace:Community.VisualStudio.Toolkit;assembly=Community.VisualStudio.Toolkit"
7+
toolkit:Themes.UseVsTheme="True" Icon="{x:Null}">
8+
<Grid Margin="0,10,0,0">
9+
<Grid.RowDefinitions>
10+
<RowDefinition Height="auto" />
11+
<RowDefinition Height="auto" />
12+
<RowDefinition Height="auto" />
13+
</Grid.RowDefinitions>
14+
<Grid.ColumnDefinitions>
15+
<ColumnDefinition Width="auto" />
16+
<ColumnDefinition />
17+
</Grid.ColumnDefinitions>
18+
<Label Grid.Row="0" Grid.Column="0" Content="Name:" HorizontalAlignment="Right" VerticalAlignment="Top" FontWeight="SemiBold" />
19+
<TextBox Margin="0,0,10,0" Grid.Row="0" Grid.Column="1" Name="txtName" VerticalAlignment="Top" HorizontalAlignment="Stretch" MinWidth="150"/>
20+
<Label Margin="0,5,0,0" Grid.Row="1" Grid.Column="0" Content="Secret:" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="SemiBold" />
21+
<TextBox Margin="0,5,10,0" Grid.Row="1" Grid.Column="1" Name="txtSecret" AcceptsReturn="True" VerticalContentAlignment="Top" Height="100" TextWrapping="Wrap" VerticalAlignment="Top" HorizontalAlignment="Stretch" MinWidth="210" />
22+
23+
<StackPanel Grid.Row="2" Grid.Column="2" HorizontalAlignment="Right" Orientation="Horizontal" Margin="0,5,0,0">
24+
<Button Content="Save" Margin="10,0,0,0" VerticalAlignment="Center" Width="75" Height="23" Name="btnCreate" Click="Save_Click" />
25+
<Button Content="Cancel" Margin="10,0" VerticalAlignment="Center" Width="75" Height="23" IsDefault="True" Name="btnCancel" Click="Cancel_Click" />
26+
</StackPanel>
27+
</Grid>
28+
</Window>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Text.RegularExpressions;
2+
using System.Windows;
3+
4+
namespace GitHubActionsVS.UserControls;
5+
/// <summary>
6+
/// Interaction logic for AddEditSecret.xaml
7+
/// </summary>
8+
public partial class AddEditSecret : Window
9+
{
10+
public AddEditSecret(string secretName)
11+
{
12+
InitializeComponent();
13+
txtName.Text = secretName;
14+
txtName.IsEnabled = string.IsNullOrWhiteSpace(secretName);
15+
Title = string.IsNullOrWhiteSpace(secretName) ? "Add Secret" : "Edit Secret";
16+
btnCreate.Content = string.IsNullOrWhiteSpace(secretName) ? "Create" : "Update";
17+
}
18+
19+
public string SecretName => txtName.Text.Trim();
20+
public string SecretValue => txtSecret.Text.Trim();
21+
22+
private void Save_Click(object sender, RoutedEventArgs e)
23+
{
24+
// Secret names can only contain alphanumeric characters ([a-z], [A-Z], [0-9]) or underscores (_). Spaces are not allowed. Must start with a letter ([a-z], [A-Z]) or underscores (_).
25+
Regex rx = new Regex("^[a-zA-Z_][a-zA-Z0-9_]*$");
26+
if (rx.IsMatch(txtName.Text))
27+
{
28+
DialogResult = true;
29+
Close();
30+
}
31+
else
32+
{
33+
Community.VisualStudio.Toolkit.MessageBox mb = new();
34+
mb.ShowError("Secret names can only contain alphanumeric characters ([a-z], [A-Z], [0-9]) or underscores (_). Spaces are not allowed. Must start with a letter ([a-z], [A-Z]) or underscores (_).", "Invalid Secret Name");
35+
}
36+
}
37+
38+
private void Cancel_Click(object sender, RoutedEventArgs e)
39+
{
40+
DialogResult = false;
41+
Close();
42+
}
43+
}

src/lib/win32/arm64/git2-e632535.dll

-1.39 MB
Binary file not shown.

src/lib/win32/x86/git2-e632535.dll

-1.32 MB
Binary file not shown.

src/libsodium.dll

305 KB
Binary file not shown.

0 commit comments

Comments
 (0)