From 762386bbc566b0df615f089488652b364a448eb9 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Mon, 6 Jul 2026 08:26:34 +0200 Subject: [PATCH 1/3] Standardize README landing page --- README.md | 302 ++---------------------------------------------------- 1 file changed, 11 insertions(+), 291 deletions(-) diff --git a/README.md b/README.md index 00a1f92a..634f34fa 100644 --- a/README.md +++ b/README.md @@ -1,307 +1,27 @@ # Context -Modules typically handle two types of data that benefit from persistent secure storage and management: module settings and user settings and secrets. -This module introduces the concept of `Contexts`, which enable persistent and secure data storage for PowerShell modules. It allows module developers -to separate user and module data from the module code, enabling users to resume their work without needing to reconfigure the module or log in again, -provided the service supports session refresh mechanisms (e.g., refresh tokens). - -The module uses NaCl-based encryption, provided by the `libsodium` library (delivered via the [`Sodium`](https://github.com/PSModule/Sodium) module), -to encrypt and decrypt `Context` data. The [`Sodium`](https://github.com/PSModule/Sodium) module is automatically installed when you install this -module. - -## What is a `Context`? - -The concept of `Context` is widely used to represent a collection of data that is relevant to a specific use-case. In this module, -a `Context` is a way to securely persist user and module data and offers a set of functions to manage this across modules that implement it. -Data that is stored in a `Context` can include user-specific settings, secrets, and module configuration data. -A `Context` is identified by a unique ID in the module that implements it. -Any data that can be represented in JSON format can be stored in a `Context`. - -## Grouping Contexts into Vaults - -Contexts can be grouped into `ContextVaults`, which are logical containers for related contexts. This allows for organization and management of -contexts, especially when dealing with multiple users or modules. Vaults are automatically created when you store a context, and they can be managed -using the provided functions in this module. - -### Directory Structure - -```plaintext -$HOME/.contextvaults/ -├── GitHub/ -│ ├── 64a5bbaf-96b8-4090-a77d-75e02ab6c4e0.json -│ ├── f201dc50-c163-4a7a-8d69-aea7f696737d.json -│ └── shard -├── AzureDevOps/ -│ ├── cf49fceb-38d1-47da-a0ae-219ac40e4d8c.json -│ ├── b521a424-dd1c-445b-a0d6-c26a29d93654.json -│ └── shard -``` - -In this example there are two named vaults (`GitHub` and `AzureDevOps`). Each vault contains its own `shard` file (for encryption) and two context -files (with unique GUID filenames) that store encrypted context data. Contexts in different vaults are completely isolated from each other. - -### 1. Storing data (object or dictionary) to disk using `Set-Context` - -To store data to disk, use the `Set-Context` function. The function needs an ID and the data object. -The object can be anything that can be converted and represented in JSON format. - -```pwsh -Set-Context -ID 'john_doe' -Vault 'GitHub' -Context ([PSCustomObject]@{ - Username = 'john_doe' - AuthToken = 'ghp_12345ABCDE67890FGHIJ' | ConvertTo-SecureString -AsPlainText -Force # gitleaks:allow - LoginTime = Get-Date - IsTwoFactorAuth = $true - TwoFactorMethods = @('TOTP', 'SMS') -}) -``` - -### 2. The object is converted to JSON and prepared for encryption - -The object that is passed into `Set-Context` is first analyzed. If the object contains any `SecureString` values, they are converted to plain-text and -prefixed with `[SECURESTRING]`. This indicates that these values should be restored back to `SecureString`. The whole object is then converted to a -JSON string. - -```json -{ - "ID": "john_doe", - "Username": "john_doe", - "AuthToken": "[SECURESTRING]ghp_12345ABCDE67890FGHIJ", - "LoginTime": "2024-11-21T21:16:56.2518249+01:00", - "IsTwoFactorAuth": true, - "TwoFactorMethods": ["TOTP", "SMS"] -} -``` - -### 3. Storing the context object to disk - -Finally the data is encrypted using the `Sodium` module and saved to disk. The file is stored in the user's home -directory `$HOME/.contextvaults//.json`, where `` is a generated GUID, providing a unique name for the file. -The encrypted JSON representation of the data is added to metadata object that holds other info such as the ID of the `Context` and the path to the -file where it is stored. - -```json -{ - "ID": "github.com/john_doe", - "Vault": "GitHub", - "Path": "C:\\Users\\JohnDoe\\.contextvaults\\GitHub\\d2edaa6e-95a1-41a0-b6ef-0ecc5d116030.json", - "Context": "0kGmtbQiEtih7 --< encrypted context data >-- ceqbMiBilUvEzO1Lk" -} -``` - -The metadata can be accessed using the `Get-ContextInfo` function. +Context is a PowerShell module for managing contexts with secrets and variables. ## Installation -You can install the module from the PowerShell Gallery using the following command: +Install the module from the PowerShell Gallery: ```powershell -Install-PSResource -Name Context -TrustRepository -Repository PSGallery +Install-PSResource -Name Context Import-Module -Name Context ``` -## Implementation Guide for Module Developers - -This section shows how to integrate the Context module into your PowerShell module to provide persistent, secure storage for module settings and user data. - -### Quick Start - -The simplest way to implement Contexts is using `Set-Context`, which automatically creates the vault if it doesn't exist: - -```pwsh -# Store module configuration - vault is created automatically -Set-Context -ID 'ModuleSettings' -Vault 'MyModule' -Context @{ - DefaultApiEndpoint = 'https://api.example.com' - TimeoutSeconds = 30 -} - -# Store user credentials -Set-Context -ID 'User.JohnDoe' -Vault 'MyModule' -Context @{ - Username = 'johndoe' - ApiKey = 'secret-key' | ConvertTo-SecureString -AsPlainText -Force - LastLogin = Get-Date -} -``` - -### Best Practices for Module Integration - -#### 1. Create Wrapper Functions - -Create module-specific wrapper functions to provide a familiar interface for your users: - -```pwsh -# In your module -function Set-MyModuleContext { - param( - [Parameter(Mandatory)] - [string] $ID, - - [Parameter(Mandatory)] - [object] $Context - ) - - Set-Context -ID $ID -Vault 'MyModule' -Context $Context -} - -function Get-MyModuleContext { - param( - [string] $ID = '*' - ) - - Get-Context -ID $ID -Vault 'MyModule' -} -``` +## Documentation -#### 2. Module Configuration Pattern +Documentation is published at [psmodule.io/Context](https://psmodule.io/Context/). -Store module-wide settings that persist across sessions: +Use PowerShell help and command discovery for module details: -```pwsh -# Initialize module settings on first load -if (-not (Get-Context -ID 'Settings' -Vault 'MyModule' -ErrorAction SilentlyContinue)) { - Set-Context -ID 'Settings' -Vault 'MyModule' -Context @{ - DefaultUser = $null - ApiEndpoint = 'https://api.example.com' - EnableLogging = $false - } -} -``` - -#### 3. User Context Pattern - -Handle multiple user accounts within your module: - -```pwsh -# Store user-specific data -function Connect-MyService { - param( - [Parameter(Mandatory)] - [string] $Username, - - [Parameter(Mandatory)] - [SecureString] $ApiKey - ) - - # Store user context - Set-Context -ID "User.$Username" -Vault 'MyModule' -Context @{ - Username = $Username - ApiKey = $ApiKey - ConnectedAt = Get-Date - } - - # Update module settings to remember the current user - $moduleSettings = Get-Context -ID 'Settings' -Vault 'MyModule' - $moduleSettings.DefaultUser = $Username - Set-Context -ID 'Settings' -Vault 'MyModule' -Context $moduleSettings -} -``` - -### Complete Example - -Here's a complete example of how to implement Contexts in a hypothetical GitHub module: - -```pwsh -# Module initialization (in .psm1 file) -$VaultName = 'GitHub' - -# Initialize module settings if they don't exist -if (-not (Get-Context -ID 'ModuleSettings' -Vault $VaultName -ErrorAction SilentlyContinue)) { - Set-Context -ID 'ModuleSettings' -Vault $VaultName -Context @{ - DefaultOrganization = $null - ApiEndpoint = 'https://api.github.com' - DefaultUser = $null - } -} - -# Public function to connect user -function Connect-GitHub { - param( - [Parameter(Mandatory)] - [string] $Username, - - [Parameter(Mandatory)] - [string] $Token - ) - - # Store user context with secure token - Set-Context -ID "User.$Username" -Vault $VaultName -Context @{ - Username = $Username - Token = $Token | ConvertTo-SecureString -AsPlainText -Force - Organizations = @() - LastConnected = Get-Date - } - - # Set as default user - $settings = Get-Context -ID 'ModuleSettings' -Vault $VaultName - $settings.DefaultUser = $Username - Set-Context -ID 'ModuleSettings' -Vault $VaultName -Context $settings - - Write-Host "Connected to GitHub as $Username" -} - -# Public function to get current user context -function Get-GitHubUser { - $settings = Get-Context -ID 'ModuleSettings' -Vault $VaultName - if ($settings.DefaultUser) { - Get-Context -ID "User.$($settings.DefaultUser)" -Vault $VaultName - } -} -``` - -### Key Implementation Points - -- **Automatic Vault Creation**: `Set-Context` creates the vault automatically if it doesn't exist, and preserves existing encryption keys -- **Consistent Vault Naming**: Use your module name as the vault name for organization -- **Wrapper Functions**: Provide module-specific functions that hide the vault parameter from users -- **SecureString Support**: The Context module automatically handles `SecureString` encryption and decryption -- **Module Settings**: Store module-wide configuration separate from user-specific data - -## Vault Management (Advanced) - -For most use cases, you don't need to manage vaults directly since `Set-Context` creates them automatically. However, you can manage vaults explicitly when needed: - -```pwsh -# List all vaults -Get-ContextVault - -# Get specific vault information -Get-ContextVault -Name "MyModule" - -# Remove a vault and all its contexts (use with caution) -Remove-ContextVault -Name "OldModule" -``` - -## Context Operations - -### Basic Operations - -```pwsh -# Store a context (creates vault automatically) -Set-Context -ID 'UserSettings' -Vault 'MyModule' -Context @{ - Theme = 'Dark' - Language = 'en-US' -} - -# Retrieve a context -Get-Context -ID 'UserSettings' -Vault 'MyModule' - -# Get all contexts in a vault -Get-Context -Vault 'MyModule' - -# Remove a context -Remove-Context -ID 'UserSettings' -Vault 'MyModule' - -# Rename a context -Rename-Context -ID 'OldName' -NewID 'NewName' -Vault 'MyModule' - -# Get context metadata (without decrypting) -Get-ContextInfo -Vault 'MyModule' +```powershell +Get-Command -Module Context +Get-Help -Examples ``` -## Important Notes +## Contributing -- **Vault Requirement**: Every context must be stored in a named vault - there is no default vault -- **Automatic Vault Creation**: `Set-Context` automatically creates vaults if they don't exist -- **Encryption Key Preservation**: Existing vault encryption keys are preserved when using `Set-Context` -- **Vault Isolation**: Each vault is isolated with its own encryption keys and storage directory -- **Storage Location**: Vaults are stored under `$HOME/.contextvaults//` -- **SecureString Support**: The module automatically handles encryption/decryption of `SecureString` values +Issues and pull requests are welcome. Please use the repository issue tracker to report bugs, request features, or discuss improvements. From 3751a87180bf982506acba19d1d809aaf23a05e2 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Mon, 6 Jul 2026 10:37:52 +0200 Subject: [PATCH 2/3] Address Copilot README review --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 634f34fa..5a6306f1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Context is a PowerShell module for managing contexts with secrets and variables. Install the module from the PowerShell Gallery: ```powershell -Install-PSResource -Name Context +Install-PSResource -Name Context -Repository PSGallery Import-Module -Name Context ``` @@ -19,7 +19,7 @@ Use PowerShell help and command discovery for module details: ```powershell Get-Command -Module Context -Get-Help -Examples +Get-Help Get-Context -Examples ``` ## Contributing From 13ae1e9e1f78c072e156474a18401f4c13c6eb39 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 12 Jul 2026 12:00:33 +0200 Subject: [PATCH 3/3] Restore conceptual overview, vaults model, and usage showcase to README --- README.md | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5a6306f1..13f21983 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,132 @@ # Context -Context is a PowerShell module for managing contexts with secrets and variables. +Most modules work with two kinds of data that benefit from persistent, secure storage: module settings and the user's own +settings and secrets. Context provides a single, secure place to keep that data so it lives separately from your module code. +Users can pick up where they left off without reconfiguring the module or signing in again, as long as the service supports +session refresh (for example, refresh tokens). + +Context data is encrypted at rest using NaCl-based encryption from the `libsodium` library, delivered through the +[`Sodium`](https://github.com/PSModule/Sodium) module. `Sodium` is installed automatically when you install this module. + +## What is a context? + +A `context` is a collection of data that is relevant to a specific use case, such as user settings, secrets, and module +configuration. Context stores that data securely and gives you a consistent set of commands to manage it across every module +that adopts it. Each context is identified by a unique ID, and anything that can be represented as JSON can be stored in it. + +When you save a context, any `SecureString` values are handled for you: they are marked, encrypted with `Sodium`, and restored +back to `SecureString` when the context is read. `Get-ContextInfo` returns a context's metadata (its ID, vault, and storage +path) without decrypting the stored data. + +## Vaults + +Contexts are grouped into vaults, which are logical containers for related contexts. Vaults keep data organized when you work +with multiple users or modules, and each vault is isolated with its own encryption key and storage directory. A vault is +created automatically the first time you store a context in it. + +Vaults live under `$HOME/.contextvaults//`. Each vault has its own `shard` file (used for encryption) and one JSON +file per context, named with a unique GUID: + +```plaintext +$HOME/.contextvaults/ +├── GitHub/ +│ ├── 64a5bbaf-96b8-4090-a77d-75e02ab6c4e0.json +│ ├── f201dc50-c163-4a7a-8d69-aea7f696737d.json +│ └── shard +├── AzureDevOps/ +│ ├── cf49fceb-38d1-47da-a0ae-219ac40e4d8c.json +│ ├── b521a424-dd1c-445b-a0d6-c26a29d93654.json +│ └── shard +``` + +Contexts in different vaults are completely isolated from each other. ## Installation Install the module from the PowerShell Gallery: ```powershell -Install-PSResource -Name Context -Repository PSGallery +Install-PSResource -Name Context Import-Module -Name Context ``` +## Usage + +### Example: Store and retrieve a context + +Store an object with `Set-Context`, then read it back with `Get-Context`. The vault is created automatically if it does not +exist, and `SecureString` values round-trip securely. + +```powershell +Set-Context -ID 'john_doe' -Vault 'GitHub' -Context ([PSCustomObject]@{ + Username = 'john_doe' + AuthToken = 'ghp_12345ABCDE67890FGHIJ' | ConvertTo-SecureString -AsPlainText -Force # gitleaks:allow + LoginTime = Get-Date + TwoFactorMethods = @('TOTP', 'SMS') +}) + +Get-Context -ID 'john_doe' -Vault 'GitHub' +``` + +### Example: Inspect metadata without decrypting + +```powershell +Get-ContextInfo -Vault 'GitHub' +``` + +### Example: Manage vaults and contexts + +```powershell +# List every vault +Get-ContextVault + +# Rename a context +Rename-Context -ID 'john_doe' -NewID 'jdoe' -Vault 'GitHub' + +# Remove a single context +Remove-Context -ID 'jdoe' -Vault 'GitHub' + +# Remove an entire vault and all of its contexts (use with caution) +Remove-ContextVault -Name 'GitHub' +``` + +## Implementing Context in your module + +Use Context to give your own module persistent, secure storage for settings and user data. The simplest approach is to call +`Set-Context` with your module name as the vault; the vault is created on first use and existing encryption keys are preserved. + +```powershell +Set-Context -ID 'ModuleSettings' -Vault 'MyModule' -Context @{ + DefaultApiEndpoint = 'https://api.example.com' + TimeoutSeconds = 30 +} +``` + +A common pattern is to wrap the Context commands so callers never need to pass the vault parameter: + +```powershell +function Set-MyModuleContext { + param( + [Parameter(Mandatory)] [string] $ID, + [Parameter(Mandatory)] [object] $Context + ) + Set-Context -ID $ID -Vault 'MyModule' -Context $Context +} + +function Get-MyModuleContext { + param([string] $ID = '*') + Get-Context -ID $ID -Vault 'MyModule' +} +``` + +Key points to keep in mind: + +- Every context lives in a named vault — there is no default vault. +- `Set-Context` creates vaults automatically and preserves existing encryption keys. +- Use your module name as the vault name to keep related contexts together. +- Store module-wide settings separately from per-user data. +- `SecureString` values are encrypted and decrypted for you. + ## Documentation Documentation is published at [psmodule.io/Context](https://psmodule.io/Context/). @@ -19,9 +135,5 @@ Use PowerShell help and command discovery for module details: ```powershell Get-Command -Module Context -Get-Help Get-Context -Examples +Get-Help -Name Get-Context -Examples ``` - -## Contributing - -Issues and pull requests are welcome. Please use the repository issue tracker to report bugs, request features, or discuss improvements.