diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md new file mode 100644 index 0000000..b145041 --- /dev/null +++ b/.cursor/rules/README.md @@ -0,0 +1,5 @@ +# Cursor (optional) + +**Cursor** users: start at **[`AGENTS.md`](../../AGENTS.md)**. All conventions live in **`skills/*/SKILL.md`**. + +This folder only points contributors to **`AGENTS.md`** so editor-specific config does not duplicate the canonical docs. diff --git a/.github/workflows/check-branch.yml b/.github/workflows/check-branch.yml index 1e2d24a..421c253 100644 --- a/.github/workflows/check-branch.yml +++ b/.github/workflows/check-branch.yml @@ -8,13 +8,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Comment PR - if: github.base_ref == 'master' && github.head_ref != 'next' + if: github.base_ref == 'master' && github.head_ref != 'development' uses: thollander/actions-comment-pull-request@v2 with: message: | - We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the next branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch. + We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the development branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch. - name: Check branch - if: github.base_ref == 'master' && github.head_ref != 'next' + if: github.base_ref == 'master' && github.head_ref != 'development' run: | - echo "ERROR: We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the next branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch." + echo "ERROR: We regret to inform you that you are currently not able to merge your changes into the master branch due to restrictions applied by our SRE team. To proceed with merging your changes, we kindly request that you create a pull request from the development branch. Our team will then review the changes and work with you to ensure a successful merge into the master branch." exit 1 \ No newline at end of file diff --git a/.github/workflows/issues-jira.yml b/.github/workflows/issues-jira.yml new file mode 100644 index 0000000..7bf0469 --- /dev/null +++ b/.github/workflows/issues-jira.yml @@ -0,0 +1,31 @@ +name: Create Jira Ticket for Github Issue + +on: + issues: + types: [opened] + +jobs: + issue-jira: + runs-on: ubuntu-latest + steps: + + - name: Login to Jira + uses: atlassian/gajira-login@master + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + - name: Create Jira Issue + id: create_jira + uses: atlassian/gajira-create@master + with: + project: ${{ secrets.JIRA_PROJECT }} + issuetype: ${{ secrets.JIRA_ISSUE_TYPE }} + summary: Github | Issue | ${{ github.event.repository.name }} | ${{ github.event.issue.title }} + description: | + *GitHub Issue:* ${{ github.event.issue.html_url }} + + *Description:* + ${{ github.event.issue.body }} + fields: "${{ secrets.ISSUES_JIRA_FIELDS }}" \ No newline at end of file diff --git a/.github/workflows/jira.yml b/.github/workflows/jira.yml deleted file mode 100644 index caa4bbd..0000000 --- a/.github/workflows/jira.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Create JIRA ISSUE -on: - pull_request: - types: [opened] -jobs: - security-jira: - if: ${{ github.actor == 'dependabot[bot]' || github.actor == 'snyk-bot' || contains(github.event.pull_request.head.ref, 'snyk-fix-') || contains(github.event.pull_request.head.ref, 'snyk-upgrade-')}} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Login into JIRA - uses: atlassian/gajira-login@master - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - - name: Create a JIRA Issue - id: create - uses: atlassian/gajira-create@master - with: - project: ${{ secrets.JIRA_PROJECT }} - issuetype: ${{ secrets.JIRA_ISSUE_TYPE }} - summary: | - ${{ github.event.pull_request.title }} - description: | - PR: ${{ github.event.pull_request.html_url }} - - fields: "${{ secrets.JIRA_FIELDS }}" - - name: Transition issue - uses: atlassian/gajira-transition@v3 - with: - issue: ${{ steps.create.outputs.issue }} - transition: ${{ secrets.JIRA_TRANSITION }} diff --git a/.github/workflows/policy-scan.yml b/.github/workflows/policy-scan.yml new file mode 100644 index 0000000..ff25923 --- /dev/null +++ b/.github/workflows/policy-scan.yml @@ -0,0 +1,46 @@ +name: Checks the security policy and configurations +on: + pull_request: + types: [opened, synchronize, reopened] +jobs: + security-policy: + if: github.event.repository.visibility == 'public' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@master + - name: Checks for SECURITY.md policy file + run: | + if ! [[ -f "SECURITY.md" || -f ".github/SECURITY.md" ]]; then exit 1; fi + security-license: + if: github.event.repository.visibility == 'public' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@master + - name: Checks for License file + run: | + expected_license_files=("LICENSE" "LICENSE.txt" "LICENSE.md" "License.txt") + license_file_found=false + current_year=$(date +"%Y") + + for license_file in "${expected_license_files[@]}"; do + if [ -f "$license_file" ]; then + license_file_found=true + # check the license file for the current year, if not exists, exit with error + if ! grep -q "$current_year" "$license_file"; then + echo "License file $license_file does not contain the current year." + exit 2 + fi + break + fi + done + + if [ "$license_file_found" = false ]; then + echo "No license file found. Please add a license file to the repository." + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/sast-scan.yml b/.github/workflows/sast-scan.yml deleted file mode 100644 index 3b9521a..0000000 --- a/.github/workflows/sast-scan.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: SAST Scan -on: - pull_request: - types: [opened, synchronize, reopened] -jobs: - security-sast: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Semgrep Scan - run: docker run -v /var/run/docker.sock:/var/run/docker.sock -v "${PWD}:/src" returntocorp/semgrep semgrep scan --config auto \ No newline at end of file diff --git a/.talismanrc b/.talismanrc index 8953f7d..85a10d9 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,4 +1,7 @@ fileignoreconfig: +- filename: .github/workflows/secrets-scan.yml + ignore_detectors: + - filecontent - filename: composer.lock checksum: 3e19a34da8e50af426a1b648f3fb067592c3df08274fa553b7204fd4d326e1df - filename: README.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d528bca --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,48 @@ +# Contentstack Utils PHP – Agent guide + +**Universal entry point** for contributors and AI agents. Detailed conventions live in **`skills/*/SKILL.md`**. + +## What this repo is + +| Field | Detail | +| --- | --- | +| **Name:** | [contentstack/utils](https://packagist.org/packages/contentstack/utils) · [GitHub](https://github.com/contentstack/contentstack-utils-php) | +| **Purpose:** | PHP library for rendering Contentstack Rich Text (RTE) content and GraphQL-shaped JSON to HTML, including embedded entries and custom render options. | +| **Out of scope (if any):** | Not an HTTP client or full Contentstack Delivery SDK; it focuses on parsing/rendering utilities used alongside other Contentstack PHP packages. | + +## Tech stack (at a glance) + +| Area | Details | +| --- | --- | +| Language | PHP `>=7.2` (Composer); CI runs on PHP 8.3. `declare(strict_types=1);` in source files. | +| Build | [Composer](https://getcomposer.org/) — `composer.json`, `composer.lock`. No compile step; autoload PSR-4 `Contentstack\Utils\` → `src/`. | +| Tests | PHPUnit 9.x via `composer test` / `phpunit`; suite in `tests/`, config `phpunit.xml`. | +| Lint / coverage | PHP_CodeSniffer (PSR-2 ruleset) — `composer check-style` / `composer fix-style`; config `phpcs.xml.dist`. Coverage/logging paths under `build/` when generated. | +| Other | Dev dependency `marc-mabe/php-enum` for enums. | + +## Commands (quick reference) + +| Command type | Command | +| --- | --- | +| Install deps | `composer install` | +| Test | `composer test` | +| Lint | `composer check-style` | +| Format (fix) | `composer fix-style` | + +**CI:** [`.github/workflows/ci.yml`](.github/workflows/ci.yml) — validates `composer.json` / lockfile, installs dependencies, runs `composer run-script test`. Other workflows: `sca-scan.yml`, `policy-scan.yml`, `issues-jira.yml`, `check-branch.yml`. + +## Where the documentation lives: skills + +| Skill | Path | What it covers | +| --- | --- | --- | +| Dev workflow | [`skills/dev-workflow/SKILL.md`](skills/dev-workflow/SKILL.md) | Branches, CI, Composer scripts, PR expectations | +| Contentstack Utils API | [`skills/contentstack-utils/SKILL.md`](skills/contentstack-utils/SKILL.md) | Public API, namespaces, extension points (`Option`, `RenderableInterface`) | +| PHP style & layout | [`skills/php-style/SKILL.md`](skills/php-style/SKILL.md) | PSR-2, PHPCS, file layout under `src/` | +| Testing | [`skills/testing/SKILL.md`](skills/testing/SKILL.md) | PHPUnit layout, mocks, coverage output | +| Code review | [`skills/code-review/SKILL.md`](skills/code-review/SKILL.md) | PR checklist aligned with this repo | + +An index with “when to use” hints is in [`skills/README.md`](skills/README.md). + +## Using Cursor (optional) + +If you use **Cursor**, [`.cursor/rules/README.md`](.cursor/rules/README.md) only points to **`AGENTS.md`**—same docs as everyone else. diff --git a/CODEOWNERS b/CODEOWNERS index 0773923..785adb4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,9 @@ -* @contentstack/security-admin \ No newline at end of file +* @contentstack/devex-pr-reviewers + +.github/workflows/sca-scan.yml @contentstack/security-admin + +**/.snyk @contentstack/security-admin + +.github/workflows/policy-scan.yml @contentstack/security-admin + +.github/workflows/issues-jira.yml @contentstack/security-admin diff --git a/LICENSE.md b/LICENSE.md index 1e02d05..d7e40d6 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2016-2024 Contentstack +Copyright (c) 2016-2026 Contentstack > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal diff --git a/skills/README.md b/skills/README.md new file mode 100644 index 0000000..f54ffac --- /dev/null +++ b/skills/README.md @@ -0,0 +1,15 @@ +# Skills – Contentstack Utils PHP + +Source of truth for detailed guidance. Read [`AGENTS.md`](../AGENTS.md) first, then open the skill that matches your task. + +## When to use which skill + +| Skill folder | Use when | +| --- | --- | +| [`dev-workflow`](dev-workflow/SKILL.md) | Running installs/tests, understanding CI, branch rules for PRs to `master` | +| [`contentstack-utils`](contentstack-utils/SKILL.md) | Changing public APIs, `Utils` / `GQL`, parsers, models, or embed rendering | +| [`php-style`](php-style/SKILL.md) | Code style, PHPCS/PSR-2, namespaces, or `src/` layout | +| [`testing`](testing/SKILL.md) | Adding or changing PHPUnit tests, mocks, or coverage | +| [`code-review`](code-review/SKILL.md) | Preparing or reviewing a PR for this repository | + +Each folder contains `SKILL.md` with YAML frontmatter (`name`, `description`). diff --git a/skills/code-review/SKILL.md b/skills/code-review/SKILL.md new file mode 100644 index 0000000..811ad3a --- /dev/null +++ b/skills/code-review/SKILL.md @@ -0,0 +1,34 @@ +--- +name: code-review +description: Use when reviewing or preparing a PR — tests, style, SemVer, docs, and branch rules for this repository. +--- + +# Code review – Contentstack Utils PHP + +## When to use + +- Authoring a pull request into this repo +- Reviewing someone else’s PR for completeness and repo policy + +## Instructions + +### Checklist + +- **Tests:** New or changed behavior has PHPUnit coverage; `composer test` passes. +- **Style:** `composer check-style` passes (PSR-2 via PHPCS). +- **Docs:** User-visible behavior changes reflected in [`README.md`](../../README.md) or other maintainer-facing docs as appropriate. +- **API / SemVer:** Public signatures and documented behavior follow semantic versioning expectations per [`CONTRIBUTING.md`](../../CONTRIBUTING.md). +- **Branch policy:** PRs targeting **`master`** must come from the **`next`** branch per [`.github/workflows/check-branch.yml`](../../.github/workflows/check-branch.yml); confirm with the team if process changes. +- **Commits:** Prefer coherent history; squash noisy WIP commits when requested. + +### Severity (optional labels) + +- **Blocker:** Breaks tests, CI, or documented security/policy requirements. +- **Major:** Missing tests for non-trivial logic, public API breakage without version strategy, or policy violations (e.g. wrong base branch). +- **Minor:** Style nits, naming, or internal refactors with no contract change. + +## References + +- [`CONTRIBUTING.md`](../../CONTRIBUTING.md) +- [`PULL_REQUEST_TEMPLATE.md`](../../PULL_REQUEST_TEMPLATE.md) +- [`dev-workflow/SKILL.md`](../dev-workflow/SKILL.md) diff --git a/skills/contentstack-utils/SKILL.md b/skills/contentstack-utils/SKILL.md new file mode 100644 index 0000000..234e472 --- /dev/null +++ b/skills/contentstack-utils/SKILL.md @@ -0,0 +1,42 @@ +--- +name: contentstack-utils +description: Use when changing Utils, GQL, BaseParser, models, enums, or embed/render behavior — the library’s public surface and integration boundaries. +--- + +# Contentstack Utils API – Contentstack Utils PHP + +## When to use + +- Adding or changing HTML/RTE rendering or GraphQL JSON → HTML conversion +- Extending or implementing render callbacks (`Option`, `RenderableInterface`) +- Working with metadata, embedded items, or enum-backed node/mark types + +## Instructions + +### Package identity + +- Composer package: `contentstack/utils` ([Packagist](https://packagist.org/packages/contentstack/utils)); PSR-4 root namespace `Contentstack\Utils\` maps to `src/`. + +### Main entry points (illustrative) + +- **`Contentstack\Utils\Utils`** ([`src/Utils.php`](../../src/Utils.php)) — static helpers such as `renderContent` / `jsonToHtml` for RTE strings and JSON payloads; extends `BaseParser`. +- **`Contentstack\Utils\GQL`** ([`src/GQL.php`](../../src/GQL.php)) — `jsonToHtml` and related parsing for GraphQL-shaped content; extends `BaseParser`. +- **`Contentstack\Utils\BaseParser`** ([`src/BaseParser.php`](../../src/BaseParser.php)) — shared parsing and embedded-object resolution logic. + +### Extension / integration + +- **`Contentstack\Utils\Model\Option`** — configure rendering; subclasses override `renderMark`, `renderNode`, `renderOptions`, etc. +- **`Contentstack\Utils\Resource\RenderableInterface`** — contract for types that participate in rendering. +- **`Contentstack\Utils\Model\Metadata`** — embed metadata (e.g. style type, attributes). +- **Enums** under `Contentstack\Utils\Enum\` (`NodeType`, `MarkType`, `StyleType`, `EmbedItemType`) use `marc-mabe/php-enum`. + +### Boundaries + +- This package does not ship HTTP calls; consumers fetch data with the Contentstack PHP SDK or other clients and pass strings/objects into `Utils` / `GQL`. +- Prefer backward-compatible changes to public method signatures; follow SemVer. + +## References + +- [`testing/SKILL.md`](../testing/SKILL.md) +- [`php-style/SKILL.md`](../php-style/SKILL.md) +- [Product README — usage](../../README.md) diff --git a/skills/dev-workflow/SKILL.md b/skills/dev-workflow/SKILL.md new file mode 100644 index 0000000..e772790 --- /dev/null +++ b/skills/dev-workflow/SKILL.md @@ -0,0 +1,44 @@ +--- +name: dev-workflow +description: Use when running Composer, CI, or PRs to master/next — installs, tests, and branch policy for this repo. +--- + +# Dev workflow – Contentstack Utils PHP + +## When to use + +- Installing dependencies or running the test suite locally +- Understanding what GitHub Actions run on push/PR +- Opening or reviewing a PR and matching branch expectations + +## Instructions + +### Local setup + +- From the repo root: `composer install` (use `composer install --ignore-platform-reqs` only if you must match CI’s relaxed install; see `.github/workflows/ci.yml`). +- Run tests: `composer test` (runs PHPUnit as defined in `composer.json`). + +### Lint + +- Check: `composer check-style` (PHPCS on `src` and `tests`). +- Autofix where supported: `composer fix-style` (PHPCBF). + +### CI + +- [`ci.yml`](../../.github/workflows/ci.yml): `composer validate`, cache + `composer install`, then `composer run-script test`. +- Lint is not currently enforced in that workflow; still run `check-style` before pushing. + +### Branch / PR policy + +- [`check-branch.yml`](../../.github/workflows/check-branch.yml): PRs **into `master`** must use branch **`next`** as the head branch (automation comments and fails otherwise). +- Prefer feature branches (not your fork’s default branch name as the only source) per [`CONTRIBUTING.md`](../../CONTRIBUTING.md). + +### Releases / versioning + +- Project follows SemVer per [`CONTRIBUTING.md`](../../CONTRIBUTING.md); public API changes belong in changelog/release notes as the maintainers require. + +## References + +- [`AGENTS.md`](../../AGENTS.md) +- [`testing/SKILL.md`](../testing/SKILL.md) +- [`php-style/SKILL.md`](../php-style/SKILL.md) diff --git a/skills/php-style/SKILL.md b/skills/php-style/SKILL.md new file mode 100644 index 0000000..cf4cf18 --- /dev/null +++ b/skills/php-style/SKILL.md @@ -0,0 +1,37 @@ +--- +name: php-style +description: Use when applying PSR-2, running PHPCS, or matching src/tests layout and strict_types in this repo. +--- + +# PHP style & layout – Contentstack Utils PHP + +## When to use + +- Fixing or avoiding PHPCS violations +- Adding new classes under `src/` or tests under `tests/` +- Aligning with existing `declare(strict_types=1);` usage + +## Instructions + +### Coding standard + +- **PHPCS** ruleset: [`phpcs.xml.dist`](../../phpcs.xml.dist) extends **PSR-2** (``). +- Check: `composer check-style`; fix: `composer fix-style` (both target `src` and `tests` per `composer.json` scripts). + +### File layout + +- **Source:** `src/` — namespaces mirror directories (e.g. `Contentstack\Utils\Model\Option` → `src/Model/Option.php`). +- **Tests:** `tests/` — namespace `Contentstack\Tests\Utils\` per `composer.json` `autoload-dev`. + +### PHP version + +- `composer.json` requires `php: >=7.2`; avoid language features that require newer versions unless the project explicitly raises the minimum. + +### Strict typing + +- New PHP files in `src/` should use `declare(strict_types=1);` consistently with existing classes. + +## References + +- [`dev-workflow/SKILL.md`](../dev-workflow/SKILL.md) +- [PSR-2 coding style guide](https://www.php-fig.org/psr/psr-2/) diff --git a/skills/testing/SKILL.md b/skills/testing/SKILL.md new file mode 100644 index 0000000..d041a38 --- /dev/null +++ b/skills/testing/SKILL.md @@ -0,0 +1,40 @@ +--- +name: testing +description: Use when writing PHPUnit tests, mocks under tests/Mock, or coverage/output under build/ for this package. +--- + +# Testing – Contentstack Utils PHP + +## When to use + +- Adding or updating unit tests for `Utils`, `GQL`, models, or helpers +- Extending mocks/fixtures under `tests/Mock` or `tests/Helpers` +- Interpreting PHPUnit config, coverage, or CI test runs + +## Instructions + +### Runner and config + +- **Command:** `composer test` → PHPUnit (`phpunit/phpunit` ^9.3). +- **Config:** [`phpunit.xml`](../../phpunit.xml) — bootstrap `vendor/autoload.php`, suite directory `tests/`, whitelist coverage on `src/`. + +### Layout + +- Test classes live directly under `tests/` (e.g. `UtilsTest.php`, `GQLTest.php`, `MetadataTest.php`) plus **`tests/Mock/`** (`JsonMock.php`, `EmbedObjectMock.php`, etc.) and **`tests/Helpers/`** (`Utility.php`). + +### Coverage and reports + +- `phpunit.xml` logs JUnit, coverage (HTML, text, Clover), and testdox output under **`build/`** (e.g. `build/coverage/`, `build/logs/`). Add `build/` to `.gitignore` if generating locally; do not commit generated artifacts unless the project asks for them. + +### Expectations for contributions + +- [`CONTRIBUTING.md`](../../CONTRIBUTING.md) requires tests for changes; new behavior should include PHPUnit coverage in the same PR where feasible. + +### Credentials + +- Tests use mocks and fixtures; do not add real API keys or stack secrets to the repo. + +## References + +- [`dev-workflow/SKILL.md`](../dev-workflow/SKILL.md) +- [`contentstack-utils/SKILL.md`](../contentstack-utils/SKILL.md)