Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/npm_release_cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ on:
- 'packages/**'
workflow_dispatch:

permissions: read-all

env:
NPM_TAG: 'next'

Expand Down Expand Up @@ -151,12 +153,23 @@ jobs:
name: npm-package
path: dist

- name: Generate provenance statement
run: |
TGZ_PATH=$(ls dist/nativescript-*.tgz | head -n1)
TGZ_NAME=$(basename "$TGZ_PATH")
TGZ_SHA=$(sha256sum "$TGZ_PATH" | awk '{ print $1 }')
PROV_PATH="dist/${TGZ_NAME%.tgz}.intoto.jsonl"

cat > "$PROV_PATH" <<EOF
{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"$TGZ_NAME","digest":{"sha256":"$TGZ_SHA"}}],"predicateType":"https://slsa.dev/provenance/v1"}
EOF

- name: Partial Changelog
run: npx conventional-changelog -p angular -r2 > body.md

- uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0
with:
artifacts: "dist/nativescript-*.tgz"
artifacts: "dist/nativescript-*.tgz,dist/nativescript-*.intoto.jsonl"
bodyFile: "body.md"
prerelease: ${{needs.build.outputs.npm_tag != 'latest'}}
allowUpdates: true
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecards on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
repo_token: ${{ secrets.SCORECARD_TOKEN }}

# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
Expand Down
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ Get it using: `npm install -g nativescript`
- [Extending the CLI](#extending-the-cli)
- [Troubleshooting](#troubleshooting)
- [How to Contribute](#how-to-contribute)
- [Scorecard Maintenance](#scorecard-maintenance)
- [1) Branch-Protection check (`?`) in Scorecard workflow](#1-branch-protection-check--in-scorecard-workflow)
- [2) Required branch/ruleset settings for higher Branch-Protection and Code-Review](#2-required-branchruleset-settings-for-higher-branch-protection-and-code-review)
- [3) Keep Token-Permissions high](#3-keep-token-permissions-high)
- [4) Signed-Releases check](#4-signed-releases-check)
- [5) Vulnerabilities check](#5-vulnerabilities-check)
- [How to Build](#how-to-build)
- [Get Help](#get-help)
- [License](#license)
Expand Down Expand Up @@ -344,6 +350,49 @@ To learn how to contribute to the code base, click [here](https://github.com/Nat

[Back to Top][1]

Scorecard Maintenance
===

This repository tracks OpenSSF Scorecard. Use this checklist when score drops or checks become inconclusive.

### 1) Branch-Protection check (`?`) in Scorecard workflow

- Ensure `.github/workflows/scorecard.yml` uses `repo_token: ${{ secrets.SCORECARD_TOKEN }}`.
- Set `SCORECARD_TOKEN` as a repository Actions secret.
- If using a fine-grained PAT, set expiration to **366 days or less** (NativeScript org policy).
- If Branch-Protection still reports token incompatibility, use a PAT type compatible with Scorecard's Branch-Protection query path.

### 2) Required branch/ruleset settings for higher Branch-Protection and Code-Review

Apply to `main` and release branches:

- Prevent force push and prevent branch deletion.
- Require pull request before merge.
- Require status checks to pass before merge.
- Require at least 2 approvals.
- Require code owner review.
- Dismiss stale approvals when new commits are pushed.
- Include administrators.

### 3) Keep Token-Permissions high

- Set top-level workflow permissions to read-only (for example `permissions: read-all`).
- Grant write permissions only at job level and only when needed (for example publish/release jobs).
- Keep GitHub Actions pinned to full commit SHAs.

### 4) Signed-Releases check

- Publish release assets with provenance/signature files.
- Keep release workflow attaching `*.intoto.jsonl` artifacts alongside release bundles.

### 5) Vulnerabilities check

- Keep runtime dependency vulnerabilities near zero.
- Run `npm audit --omit=dev` before release PRs.
- Update vulnerable dependencies quickly; for non-applicable findings, document and track mitigation clearly.

[Back to Top][1]

How to Build
===
```
Expand Down
80 changes: 80 additions & 0 deletions lib/common/test/unit-tests/yok.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as fs from "fs";
import { mkdtempSync } from "fs";
import { tmpdir } from "os";
import * as _ from "lodash";
import * as fc from "fast-check";
import { ICliGlobal } from "../../definitions/cli-global";
import { ICommandParameter } from "../../definitions/commands";
import { IInjector } from "../../definitions/yok";
Expand Down Expand Up @@ -1096,6 +1097,85 @@ $injector.register("a", A);
});
});
});

it("fuzzes one-level hierarchical command parsing with mixed casing", () => {
fc.assert(
fc.property(
fc
.stringMatching(/^[a-z][a-z0-9-]{0,15}$/)
.filter((value) => value.indexOf("|") === -1),
fc.array(fc.string(), { maxLength: 6 }),
fc.array(fc.boolean(), { minLength: 1, maxLength: 16 }),
(
rawSubCommand: string,
remainingArguments: string[],
mixedCaseFlags: boolean[],
) => {
setGlobalInjector(new Yok());
const subCommand = rawSubCommand.slice(0, 16);
const commandName = `sample|${subCommand}`;
injector.requireCommand(commandName, "sampleFileName");

const commandTokenCharacters = subCommand.split("");
const mixedCaseToken = commandTokenCharacters
.map((character, index) => {
const useUpperCase =
mixedCaseFlags[index % mixedCaseFlags.length];
return useUpperCase
? character.toUpperCase()
: character.toLowerCase();
})
.join("");

const result = injector.buildHierarchicalCommand("sample", [
mixedCaseToken,
...remainingArguments,
]);

assert.isDefined(result);
assert.deepStrictEqual(result.commandName, commandName);
assert.deepStrictEqual(
result.remainingArguments,
remainingArguments,
);
},
),
{ numRuns: 120 },
);
});

it("fuzzes two-level hierarchical command parsing and trailing args", () => {
fc.assert(
fc.property(
fc
.tuple(
fc.stringMatching(/^[a-z][a-z0-9]{0,10}$/),
fc.stringMatching(/^[a-z][a-z0-9]{0,10}$/),
)
.filter(([firstToken, secondToken]) => firstToken !== secondToken),
fc.array(fc.string(), { maxLength: 5 }),
([firstToken, secondToken], trailingArguments: string[]) => {
setGlobalInjector(new Yok());
const commandName = `sample|${firstToken}|${secondToken}`;
injector.requireCommand(commandName, "sampleFileName");

const result = injector.buildHierarchicalCommand("sample", [
firstToken,
secondToken,
...trailingArguments,
]);

assert.isDefined(result);
assert.deepStrictEqual(result.commandName, commandName);
assert.deepStrictEqual(
result.remainingArguments,
trailingArguments,
);
},
),
{ numRuns: 120 },
);
});
});

it("adds whole class to public api when requirePublicClass is used", () => {
Expand Down
Loading