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
7 changes: 6 additions & 1 deletion .github/workflows/build-npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ jobs:
id-token: write # to enable use of OIDC for npm provenance
env:
WORKING_DIRECTORY: ./
INPUT_TOKEN: ${{ secrets.NPM_TOKEN }}
concurrency:
group: npm-${{ github.ref }}
cancel-in-progress: true
Expand All @@ -20,6 +19,12 @@ jobs:
with:
submodules: recursive

- name: Setup Node.js with npm registry
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Setup
uses: ./.github/actions/setup
with:
Expand Down
224 changes: 224 additions & 0 deletions .github/workflows/npm-debug-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
name: Debug npm OIDC Authentication

on:
workflow_dispatch: # Manual trigger only

jobs:
debug-npm-auth:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for OIDC

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js with npm registry
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Debug - Check environment
run: |
echo "=== Node and npm versions ==="
node --version
npm --version

echo ""
echo "=== npm config ==="
npm config list

echo ""
echo "=== Registry configuration ==="
npm config get registry

echo ""
echo "=== .npmrc contents (redacted) ==="
if [ -f ~/.npmrc ]; then
# Show structure but redact actual tokens
sed 's/=.*/=<REDACTED>/' ~/.npmrc
else
echo "No ~/.npmrc found"
fi

if [ -f .npmrc ]; then
echo ""
echo "=== Project .npmrc (redacted) ==="
sed 's/=.*/=<REDACTED>/' .npmrc
fi

- name: Debug - Check OIDC token availability
id: oidc-check
continue-on-error: true
run: |
echo "=== OIDC Token Check ==="
OIDC_OK=true
if [ -n "$ACTIONS_ID_TOKEN_REQUEST_URL" ]; then
echo "✅ OIDC token request URL is set"
echo "URL prefix: ${ACTIONS_ID_TOKEN_REQUEST_URL:0:50}..."
else
echo "❌ OIDC token request URL is NOT set"
echo "Make sure 'id-token: write' permission is configured"
OIDC_OK=false
fi

if [ -n "$ACTIONS_ID_TOKEN_REQUEST_TOKEN" ]; then
echo "✅ OIDC token request token is available"
else
echo "❌ OIDC token request token is NOT available"
OIDC_OK=false
fi

if [ "$OIDC_OK" = "false" ]; then
exit 1
fi

- name: Debug - Test npm authentication
id: npm-auth
continue-on-error: true
run: |
echo "=== Testing npm whoami ==="
if npm whoami 2>&1; then
echo "✅ Successfully authenticated with npm"
else
echo "❌ npm whoami failed - not authenticated"
exit 1
fi

- name: Debug - Check package info
run: |
echo "=== Package.json info ==="
if [ -f package.json ]; then
echo "Package name: $(jq -r '.name' package.json)"
echo "Package version: $(jq -r '.version' package.json)"
echo "Repository: $(jq -r '.repository.url // .repository // "not set"' package.json)"
else
echo "No package.json found in root"
fi

- name: Debug - Check access to @shopify scope
run: |
echo "=== Checking @shopify scope access ==="

echo ""
echo "Packages you can access in @shopify scope:"
npm access list packages @shopify 2>&1 || echo "Could not list packages (may need org membership)"

echo ""
echo "=== Checking specific package access ==="
npm access list collaborators @shopify/react-native-skia 2>&1 || echo "Could not list collaborators"

- name: Debug - Check npm org membership
run: |
echo "=== Organization membership check ==="
npm org ls shopify 2>&1 || echo "Could not list org members (may not have permission)"

- name: Setup
uses: ./.github/actions/setup
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Debug - Dry run publish test
id: dry-run
continue-on-error: true
run: |
echo "=== Attempting dry-run publish ==="
echo "This will NOT actually publish, just test if it would work"

# Build the project using yarn (this is a yarn monorepo)
echo "Running build first..."
if ! yarn build; then
echo "❌ Build step failed"
exit 1
fi

# Try dry-run publish from the skia package
cd packages/skia
if ! npm publish --dry-run --provenance --access public 2>&1; then
echo "❌ Dry-run publish failed"
exit 1
fi
echo "✅ Dry-run publish succeeded"

- name: Debug - Check provenance requirements
run: |
echo "=== Provenance publishing requirements ==="
echo ""
echo "For provenance publishing to work, you need:"
echo "1. ✅ id-token: write permission (set in this workflow)"
echo "2. Package must be linked to this GitHub repo on npmjs.com"
echo "3. Publishing from a GitHub Actions workflow"
echo ""
echo "Current repository: $GITHUB_REPOSITORY"
echo "Current ref: $GITHUB_REF"
echo "Current SHA: $GITHUB_SHA"
echo ""
echo "Check https://www.npmjs.com/package/@shopify/react-native-skia/access"
echo "to verify this repo is configured for publishing"

- name: Summary
run: |
echo ""
echo "========================================"
echo " DEBUG SUMMARY"
echo "========================================"
echo ""
echo "If you see authentication failures above, check:"
echo ""
echo "1. Is this repo configured in npm package settings?"
echo " → Go to npmjs.com → @shopify/react-native-skia → Settings → Publishing access"
echo " → Verify '$GITHUB_REPOSITORY' is listed"
echo ""
echo "2. Do you have the right npm org permissions?"
echo " → You need publish access to the @shopify scope"
echo ""
echo "3. Is the workflow running from the right branch/context?"
echo " → Some orgs restrict publishing to specific branches"
echo ""
echo "4. Check npm's provenance documentation:"
echo " → https://docs.npmjs.com/generating-provenance-statements"
echo ""

- name: Final validation
run: |
echo ""
echo "========================================"
echo " VALIDATION RESULTS"
echo "========================================"
echo ""
FAILED=false

if [ "${{ steps.oidc-check.outcome }}" = "failure" ]; then
echo "❌ OIDC token check: FAILED"
FAILED=true
else
echo "✅ OIDC token check: PASSED"
fi

if [ "${{ steps.npm-auth.outcome }}" = "failure" ]; then
echo "❌ npm authentication: FAILED"
FAILED=true
else
echo "✅ npm authentication: PASSED"
fi

if [ "${{ steps.dry-run.outcome }}" = "failure" ]; then
echo "❌ Dry-run publish: FAILED"
FAILED=true
else
echo "✅ Dry-run publish: PASSED"
fi

echo ""
if [ "$FAILED" = "true" ]; then
echo "========================================"
echo " ❌ OVERALL: SOME CHECKS FAILED"
echo "========================================"
exit 1
else
echo "========================================"
echo " ✅ OVERALL: ALL CHECKS PASSED"
echo "========================================"
fi
25 changes: 7 additions & 18 deletions apps/example/src/Examples/API/Snapshot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
useWindowDimensions,
ScrollView,
} from "react-native";
import Svg, { Circle, Rect } from "react-native-svg";
import type { SkImage } from "@shopify/react-native-skia";
import {
Canvas,
Expand Down Expand Up @@ -54,7 +55,7 @@ export const Snapshot = () => {

return (
<View style={{ flex: 1 }}>
<View ref={viewRef} style={styles.view}>
<View ref={viewRef} style={styles.view} collapsable={false}>
<Component />
</View>
<Button title="Take snapshot" onPress={takeSnapshot} />
Expand Down Expand Up @@ -114,23 +115,11 @@ const Component = () => {
</View>
<Text>Hello World!</Text>
<View style={{ flexDirection: "row" }}>
<View
style={{
width: 80,
height: 80,
backgroundColor: "blue",
opacity: 0.5,
}}
>
<View
style={{
width: 40,
height: 40,
backgroundColor: "green",
opacity: 0.5,
}}
/>
</View>
<Svg width={80} height={80} viewBox="0 0 80 80">
<Rect x={0} y={0} width={80} height={80} fill="blue" opacity={0.5} />
<Circle cx={40} cy={40} r={25} fill="green" opacity={0.7} />
<Rect x={30} y={30} width={20} height={20} fill="red" opacity={0.5} />
</Svg>
<View
style={{
width: 40,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ private static Paint createPaint() {
return paint;
}

private static boolean isSvgView(View view) {
try {
String className = view.getClass().getName();
return className != null && className.startsWith("com.horcrux.svg");
} catch (Throwable t) {
Log.e("ViewScreenshotService", "Error checking if view is SVG", t);
return false;
}
}

private static void renderViewToCanvas(Canvas canvas, View view, Paint paint, float parentOpacity) {
float combinedOpacity = parentOpacity * view.getAlpha();
canvas.save();
Expand All @@ -83,7 +93,7 @@ private static void renderViewToCanvas(Canvas canvas, View view, Paint paint, fl
canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom);
}

if (view instanceof ViewGroup) {
if (view instanceof ViewGroup && !isSvgView(view)) {
ViewGroup group = (ViewGroup) view;
drawBackgroundIfPresent(canvas, view, combinedOpacity);
drawChildren(canvas, group, paint, combinedOpacity);
Expand Down
Loading