sf-plugin-permission-sets 0.0.0-dev → 0.0.0-dev.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,16 +16,17 @@ Stop clicking through Setup to grant access. Commit a YAML file, open a PR, let
16
16
  - [Quick start](#quick-start)
17
17
  - [Permission files](#permission-files)
18
18
  - [Organizing files](#organizing-files)
19
+ - [Validations](#validations)
19
20
  - [Modes](#modes)
20
21
  - [Commands](#commands)
21
- - [CI/CD](#cicd)
22
22
  - [Inspiration & equivalents](#inspiration--equivalents)
23
+ - [Versioning](#versioning)
23
24
 
24
25
  ---
25
26
 
26
27
  ## Why
27
28
 
28
- Permission set assignments drift. People get access for a project and keep it forever. Offboarding misses a set. Nobody can answer "who can see X and why?" without a SOQL spelunking session.
29
+ Permission set assignments drift. People get access for a project and keep it forever. Offboarding misses a set. Nobody can answer "who can see X and why?" without a SOQL spelunking session. And in higher environments those grants happen by hand in Setup, with no review and no trail.
29
30
 
30
31
  This plugin makes the desired state **declarative and reviewable**:
31
32
 
@@ -34,6 +35,8 @@ This plugin makes the desired state **declarative and reviewable**:
34
35
  - ✅ **Safe by default:** deletions are opt-in and guarded by a delete threshold.
35
36
  - ✅ **CI-native:** fully offline `check`, exit codes for gating, and `--json` on every command.
36
37
  - ✅ **Flexible at the edges:** pick your file layout (by permission set or by user) and your sync mode.
38
+ - ✅ **GitOps for access, the SFDX way:** assignments live in source and ship through the same git and CI pipeline as your metadata, instead of being clicked into Setup by hand.
39
+ - ✅ **Fewer hands in Setup for higher environments:** because access is applied from git through CI, fewer people need direct Setup access in UAT and production, and every change is a reviewed pull request with a git audit trail.
37
40
 
38
41
  ## Install
39
42
 
@@ -153,6 +156,18 @@ sf ps apply -o qa --file "permissions/qa/*.yml"
153
156
 
154
157
  The two compose: a directory per environment, each split into functional files.
155
158
 
159
+ ## Validations
160
+
161
+ Every run checks the files first. `check` runs the offline checks with no org, and `validate` adds the org-side checks. When files merge, most overlaps are unions rather than errors.
162
+
163
+ | Situation | Checked by | Severity | Result |
164
+ | --- | --- | :---: | --- |
165
+ | Same username key appears twice in one file | `check` (offline) | ❌ error | Rejected, the intent is ambiguous |
166
+ | Same target listed twice for a user, like `[Sales_Manager, Sales_Manager]` | `check` (offline) | ⚠️ warning | Deduped |
167
+ | A user with no scopes, or an empty list | `check` (offline) | ⚠️ warning | Ignored as a no-op |
168
+ | Same user in two files with different targets | `check` (offline) | ✅ ok | Merged into one model, the point of slicing |
169
+ | Declared user, permission set, group, or license missing or not unique | `validate` (online) | ❌ error | Run fails before any change |
170
+
156
171
  ## Modes
157
172
 
158
173
  A run performs two atomic operations: **add** missing assignments and **remove** undeclared ones. The mode selects which it actually executes. Set it with `--mode` (default `additive`):
@@ -188,11 +203,11 @@ FLAGS
188
203
  --strict Treat warnings as errors.
189
204
 
190
205
  CHECKS
191
- valid YAML & schema (unknown keys rejected)
192
- duplicate assignees / duplicate (user, target) pairs
193
- conflicting intent across files
194
- empty or malformed assignee usernames
195
- internal referential integrity
206
+ - valid YAML & schema (unknown keys rejected)
207
+ - duplicate assignees / duplicate (user, target) pairs
208
+ - conflicting intent across files
209
+ - empty or malformed assignee usernames
210
+ - internal referential integrity
196
211
  ```
197
212
 
198
213
  ### `sf ps validate`
@@ -277,69 +292,48 @@ FLAGS
277
292
  --permission-sets=<names> Comma-separated list to export (default: all assignable).
278
293
  ```
279
294
 
280
- ## CI/CD
295
+ ## Inspiration & equivalents
296
+
297
+ This plugin's command surface borrows ideas from tools you already know:
281
298
 
282
- A typical ladder: lint on every PR, plan against a sandbox, apply on merge:
299
+ - [Terraform](https://developer.hashicorp.com/terraform/docs)
300
+ - [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/)
301
+ - [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/)
302
+ - [Salesforce CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference.htm)
283
303
 
284
- ```yaml
285
- # .github/workflows/ps-gitops.yml
286
- name: ps-gitops
287
- on:
288
- pull_request:
289
- push:
290
- branches: [main]
291
-
292
- jobs:
293
- check:
294
- runs-on: ubuntu-latest
295
- steps:
296
- - uses: actions/checkout@v4
297
- - run: npm install -g @salesforce/cli
298
- - run: sf plugins install sf-plugin-permission-sets
299
- - run: sf ps check --file "permissions/*.yml" --strict
300
-
301
- plan:
302
- if: github.event_name == 'pull_request'
303
- needs: check
304
- runs-on: ubuntu-latest
305
- steps:
306
- - uses: actions/checkout@v4
307
- - run: npm install -g @salesforce/cli
308
- - run: sf plugins install sf-plugin-permission-sets
309
- # Auth via Sfdx auth URL stored in a secrets manager, never hardcode credentials
310
- - run: echo "$SF_AUTH_URL" | sf org login sfdx-url --sfdx-url-stdin --alias target
311
- env:
312
- SF_AUTH_URL: ${{ secrets.SF_AUTH_URL }}
313
- - run: sf ps plan -o target --file "permissions/*.yml" --mode sync --fail-on-drift
314
-
315
- apply:
316
- if: github.ref == 'refs/heads/main' && github.event_name == 'push'
317
- needs: check
318
- runs-on: ubuntu-latest
319
- steps:
320
- - uses: actions/checkout@v4
321
- - run: npm install -g @salesforce/cli
322
- - run: sf plugins install sf-plugin-permission-sets
323
- - run: echo "$SF_AUTH_URL" | sf org login sfdx-url --sfdx-url-stdin --alias target
324
- env:
325
- SF_AUTH_URL: ${{ secrets.SF_AUTH_URL }}
326
- - run: sf ps apply -o target --file "permissions/*.yml" --mode sync --no-prompt --max-deletes 25
327
- ```
304
+ ## Versioning
328
305
 
329
- > **Credentials:** the plugin never reads or stores secrets itself. It uses orgs you've already authenticated with `sf`. In CI, inject auth from your platform's secrets store (as above), not from committed files.
306
+ Releases follow [semantic versioning](https://semver.org). Snapshots are automatic, real releases are a manual decision.
330
307
 
331
- ## Inspiration & equivalents
308
+ **Automatic, no action needed:**
309
+
310
+ - Every push to `main` publishes a snapshot `0.0.0-dev.<run>` to the `dev` dist-tag.
311
+ - Creating a release triggers CI to build, stamp the version from the tag, publish it with provenance, and smoke-test the result.
312
+
313
+ **Manual, you decide and trigger:**
314
+
315
+ - Choosing the version bump (patch, minor, or major).
316
+ - Creating the GitHub Release, which is what triggers the publish above.
317
+
318
+ | Bump | When | Example tag |
319
+ | --- | --- | --- |
320
+ | patch | bug fix, no behavior change | `v0.1.1` |
321
+ | minor | new backward-compatible feature | `v0.2.0` |
322
+ | major | breaking change to a command, flag, or the YAML schema | `v1.0.0` |
323
+
324
+ Cut a release with a tag off `main`:
325
+
326
+ ```bash
327
+ gh release create v0.2.0 --target main --title v0.2.0 --notes "Add ps export"
328
+ ```
332
329
 
333
- The command surface borrows deliberately from tools you already know:
330
+ | dist-tag | Published by | Install |
331
+ | --- | --- | --- |
332
+ | `latest` | manual release with a normal tag like `v1.2.0` | `sf plugins install sf-plugin-permission-sets` |
333
+ | `next` | manual release with a hyphenated tag like `v1.3.0-beta.1` | `sf plugins install sf-plugin-permission-sets@next` |
334
+ | `dev` | automatic on every push to `main` | `sf plugins install sf-plugin-permission-sets@dev` |
334
335
 
335
- | This plugin | Terraform | CloudFormation / SAM | sf core |
336
- | -------------------- | ---------------------- | ------------------------------- | -------------------------- |
337
- | `ps check` | `terraform validate` | `sam validate --lint` | n/a |
338
- | `ps validate` | `terraform plan` (refresh) | `cfn validate-template` | `project deploy validate` |
339
- | `ps plan` | `terraform plan` | `cfn create-change-set` | `project deploy preview` |
340
- | `ps apply` | `terraform apply` | `cfn execute-change-set` / `sam deploy` | `project deploy start` |
341
- | `ps export` | `terraform import` | n/a | n/a |
342
- | `--fail-on-drift` | drift in plan exit code | `cfn detect-stack-drift` | n/a |
336
+ The `next` tag is selected whenever the version contains a hyphen, not by GitHub's prerelease checkbox.
343
337
 
344
338
  ## License
345
339
 
@@ -0,0 +1,11 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export type PsInfoResult = {
3
+ name: string;
4
+ description: string;
5
+ };
6
+ export default class Info extends SfCommand<PsInfoResult> {
7
+ static readonly summary: string;
8
+ static readonly description: string;
9
+ static readonly examples: string[];
10
+ run(): Promise<PsInfoResult>;
11
+ }
@@ -0,0 +1,17 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ import { Messages } from '@salesforce/core';
3
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
4
+ const messages = Messages.loadMessages('sf-plugin-permission-sets', 'ps.info');
5
+ export default class Info extends SfCommand {
6
+ static summary = messages.getMessage('summary');
7
+ static description = messages.getMessage('description');
8
+ static examples = messages.getMessages('examples');
9
+ async run() {
10
+ await this.parse(Info);
11
+ const name = 'sf-plugin-permission-sets';
12
+ const description = 'Declarative, GitOps-style management of permission set assignments.';
13
+ this.log(messages.getMessage('info.summary', [name, description]));
14
+ return { name, description };
15
+ }
16
+ }
17
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../../../src/commands/ps/info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,2BAA2B,EAAE,SAAS,CAAC,CAAC;AAO/E,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,SAAuB;IAChD,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,IAAI,GAAG,2BAA2B,CAAC;QACzC,MAAM,WAAW,GAAG,qEAAqE,CAAC;QAC1F,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;QACnE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC/B,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ declare const _default: {};
2
+ export default _default;
package/lib/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export default {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe,EAAE,CAAC"}
@@ -0,0 +1,17 @@
1
+ # summary
2
+
3
+ Show information about the permission-sets plugin.
4
+
5
+ # description
6
+
7
+ Print the plugin name and what it does. A quick way to confirm the plugin is installed and working.
8
+
9
+ # examples
10
+
11
+ - Show plugin info:
12
+
13
+ <%= config.bin %> <%= command.id %>
14
+
15
+ # info.summary
16
+
17
+ %s - %s