diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..9c542e4d9 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,84 @@ +FROM mcr.microsoft.com/devcontainers/base:debian + +# Set non-interactive frontend for apt +ENV DEBIAN_FRONTEND=noninteractive + +# Switch to root for installing packages +USER root + +# Install additional dependencies +RUN apt update && apt install -y \ + build-essential \ + curl \ + jq \ + python3 \ + python3-pip \ + python3-venv \ + pipx \ + && apt clean \ + && rm -rf /var/lib/apt/lists/* + +# Install Node.js 20.x using NodeSource +RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ + apt update && \ + apt install -y nodejs && \ + apt clean && \ + rm -rf /var/lib/apt/lists/* + +# Install Solidity compiler using pipx (isolated environment) +RUN pipx install solc-select && \ + pipx ensurepath && \ + /root/.local/bin/solc-select install 0.8.27 && \ + /root/.local/bin/solc-select use 0.8.27 && \ + # Copy binaries to /usr/local/bin with proper permissions (not symlinks) + cp /root/.local/bin/solc /usr/local/bin/solc && \ + cp /root/.local/bin/solc-select /usr/local/bin/solc-select && \ + chmod 755 /usr/local/bin/solc && \ + chmod 755 /usr/local/bin/solc-select && \ + # Make sure pipx directory is accessible + chmod -R a+rx /root/.local/pipx && \ + # Set up for vscode user + mkdir -p /home/vscode/.solc-select && \ + cp -r /root/.solc-select/* /home/vscode/.solc-select/ && \ + chown -R vscode:vscode /home/vscode/.solc-select + +RUN npm install -g ethers@6.13.4 + +# Install cloc for code analysis +RUN npm install -g cloc + +# Install Foundry for Anvil (as root for global installation) +RUN curl -L https://foundry.paradigm.xyz | bash && \ + /root/.foundry/bin/foundryup && \ + # Copy binaries to /usr/local/bin with proper permissions + cp /root/.foundry/bin/anvil /usr/local/bin/anvil && \ + cp /root/.foundry/bin/cast /usr/local/bin/cast && \ + cp /root/.foundry/bin/forge /usr/local/bin/forge && \ + cp /root/.foundry/bin/chisel /usr/local/bin/chisel && \ + # Ensure proper permissions + chmod 755 /usr/local/bin/anvil && \ + chmod 755 /usr/local/bin/cast && \ + chmod 755 /usr/local/bin/forge && \ + chmod 755 /usr/local/bin/chisel + +# Set up pnpm +RUN corepack enable && \ + corepack prepare pnpm@9.0.6 --activate + +# Ensure all users have access to the tools +RUN chmod 755 /usr/local/bin/* && \ + # Create a directory for vscode user's binaries + mkdir -p /home/vscode/.local/bin && \ + chown -R vscode:vscode /home/vscode/.local/bin + +# Switch back to vscode user +USER vscode + +# Set environment variables +ENV PATH="/usr/local/bin:/home/vscode/.foundry/bin:/home/vscode/.local/bin:/root/.local/bin:$PATH" + +# Create .bashrc additions for PATH +RUN echo 'export PATH="/usr/local/bin:$HOME/.local/bin:$PATH"' >> $HOME/.bashrc + +# Set the default command +CMD ["sleep", "infinity"] diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 000000000..73b33e9be --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,107 @@ +# Graph Protocol Contracts Dev Container + +This directory contains configuration files for the Graph Protocol contracts development container. + +> **Note:** This dev container setup is a work in progress and will not be fully portable. + +## Overview + +The dev container provides a consistent development environment with caching to improve performance. + +### Key Components + +1. **Docker Compose Configuration**: Defines the container setup, volume mounts, and environment variables +2. **Dockerfile**: Specifies the container image and installed tools +3. **project-setup.sh**: Configures the environment after container creation +4. **host-setup.sh**: Sets up the host environment before starting the container +5. **setup-git-signing.sh**: Automatically configures Git to use SSH signing with forwarded SSH keys + +## Cache System + +The container uses a conservative caching approach to prevent cache corruption issues: + +1. **Local Cache Directories**: Each container instance maintains its own cache directories + + - `vscode-cache` → `/home/vscode/.cache` (VS Code cache) + - `vscode-config` → `/home/vscode/.config` (VS Code configuration) + - `vscode-data` → `/home/vscode/.local/share` (VS Code data) + - `vscode-bin` → `/home/vscode/.local/bin` (User binaries) + +2. **Safe Caches Only**: Only caches that won't cause cross-branch issues are configured + + - GitHub CLI: `/home/vscode/.cache/github` + - Python packages: `/home/vscode/.cache/pip` + +3. **Intentionally Not Cached**: These tools use their default cache locations to avoid contamination + - NPM (different dependency versions per branch) + - Foundry, Solidity (different compilation artifacts per branch) + - Hardhat (different build artifacts per branch) + +## Setup Instructions + +### Start the Dev Container + +To start the dev container: + +1. Open VS Code +2. Use the "Remote-Containers: Open Folder in Container" command +3. Select the repository directory (for example `/git/graphprotocol/contracts`) + +When the container starts, the `project-setup.sh` script will automatically run and: + +- Install project dependencies using pnpm +- Configure Git to use SSH signing with your forwarded SSH key +- Source shell customizations if available in PATH + +## Environment Variables + +Environment variables are defined in two places: + +1. **docker-compose.yml**: Contains most of the environment variables for tools and caching +2. **Environment File**: Personal settings are stored in `/opt/configs/graphprotocol/contracts.env` on the host + +### Git Configuration + +To enable Git commit signing, add the following settings to your environment file: + +```env +# Git settings for commit signing +GIT_USER_NAME=Your Name +GIT_USER_EMAIL=your.email@example.com +``` + +These environment variables are needed for Git commit signing to work properly. If they are not defined, Git commit signing will not be configured, but the container will still work for other purposes. + +## Troubleshooting + +### Cache Issues + +If you encounter build or compilation issues that seem related to cached artifacts: + +1. **Rebuild the container**: This will start with fresh local caches +2. **Clean project caches**: Run `pnpm clean` to clear project-specific build artifacts +3. **Clear node modules**: Delete `node_modules` and run `pnpm install` again + +### Git SSH Signing Issues + +If you encounter issues with Git SSH signing: + +1. **SSH Agent Forwarding**: Make sure SSH agent forwarding is properly set up in your VS Code settings +2. **GitHub Configuration**: Ensure your SSH key is added to GitHub as a signing key in your account settings +3. **Manual Setup**: If automatic setup fails, you can manually configure SSH signing: + +```bash +# Check available SSH keys +ssh-add -l + +# Configure Git to use SSH signing +git config --global gpg.format ssh +git config --global user.signingkey "key::ssh-ed25519 YOUR_KEY_CONTENT" +git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers +git config --global commit.gpgsign true + +# Create allowed signers file +echo "your.email@example.com ssh-ed25519 YOUR_KEY_CONTENT" > ~/.ssh/allowed_signers +``` + +For other issues, check the `project-setup.sh` and `setup-git-signing.sh` scripts for any errors. diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..8d7fb643d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,42 @@ +{ + "name": "graph contracts", + "dockerComposeFile": ["docker-compose.yml"], + "service": "dev-graph-contracts", + "features": { + "ghcr.io/devcontainers/features/git:1": { + "configureGitHubCLI": true, + "gitCredentialHelper": "cache" + }, + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/common-utils:2.5.3": {}, + "ghcr.io/devcontainers/features/node:1": { + "version": "20" + }, + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} + }, + "postCreateCommand": ".devcontainer/project-setup.sh", + "remoteUser": "vscode", + "workspaceFolder": "${localWorkspaceFolder}", + "customizations": { + "vscode": { + "extensions": [ + "rust-lang.rust-analyzer", + "tamasfe.even-better-toml", + "usernamehw.errorlens", + "yzhang.markdown-all-in-one", + "DavidAnson.vscode-markdownlint", + "shd101wyy.markdown-preview-enhanced", + "bierner.markdown-preview-github-styles", + "Gruntfuggly.todo-tree", + "ms-azuretools.vscode-docker", + "donjayamanne.githistory", + "eamodio.gitlens", + "fill-labs.dependi", + "streetsidesoftware.code-spell-checker", + "Augment.vscode-augment", + "NomicFoundation.hardhat-solidity", + "foundry-rs.foundry-vscode" + ] + } + } +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 000000000..d16a44b34 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,53 @@ +services: + dev-graph-contracts: + build: + context: . + dockerfile: Dockerfile + env_file: + - /opt/configs/graphprotocol/contracts.env + environment: + # Essential for large builds + - NODE_OPTIONS=--max-old-space-size=4096 + + # Clean development environment + - PYTHONDONTWRITEBYTECODE=1 + + # Disable interactive prompts + - COREPACK_ENABLE_DOWNLOAD_PROMPT=0 + + # Standard user directories + - XDG_CACHE_HOME=/home/vscode/.cache + - XDG_CONFIG_HOME=/home/vscode/.config + - XDG_DATA_HOME=/home/vscode/.local/share + + # Safe caches (won't cause cross-branch issues) + - GH_CONFIG_DIR=/home/vscode/.cache/github + - PIP_CACHE_DIR=/home/vscode/.cache/pip + + # pnpm cache is safe to share due to content-addressable storage + - PNPM_HOME=/home/vscode/.local/share/pnpm + - PNPM_CACHE_DIR=/home/vscode/.cache/pnpm + + # Note: NPM, Foundry, and Solidity caches are intentionally not set + # to avoid cross-branch contamination. Tools will use their default locations. + volumes: + # Git repo root + - /git:/git + + # Local directories for user data (keep local to container) + - vscode-cache:/home/vscode/.cache + - vscode-config:/home/vscode/.config + - vscode-data:/home/vscode/.local/share + - vscode-bin:/home/vscode/.local/bin + + # Shared pnpm cache (safe due to content-addressable storage) + - pnpm-store:/home/vscode/.local/share/pnpm + - pnpm-cache:/home/vscode/.cache/pnpm + +volumes: + vscode-cache: + vscode-config: + vscode-data: + vscode-bin: + pnpm-store: + pnpm-cache: diff --git a/.devcontainer/host-setup.sh b/.devcontainer/host-setup.sh new file mode 100755 index 000000000..b85093826 --- /dev/null +++ b/.devcontainer/host-setup.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Host setup script for Graph Protocol Contracts dev container +# Run this script on the host before starting the dev container +# Usage: sudo .devcontainer/host-setup.sh + +set -euo pipefail + +echo "Setting up host environment for Graph Protocol Contracts dev container..." + +# Check if running as root +if [ "$(id -u)" -ne 0 ]; then + echo "Error: This script must be run as root (sudo)" >&2 + exit 1 +fi + +CACHE_DIRS=( + "/cache/vscode-cache" + "/cache/vscode-config" + "/cache/vscode-data" + "/cache/vscode-bin" + "/cache/hardhat" + "/cache/npm" + "/cache/yarn" + "/cache/pip" + "/cache/pycache" + "/cache/solidity" + "/cache/foundry" + "/cache/github" + "/cache/apt" + "/cache/apt-lib" +) + +echo "Creating cache directories..." +for dir in "${CACHE_DIRS[@]}"; do + if [ ! -d "$dir" ]; then + echo "Creating $dir" + mkdir -p "$dir" + chmod 777 "$dir" + else + echo "$dir already exists" + fi +done + +# Note: Package-specific directories will be created by the project-setup.sh script +# inside the container, as they are tied to the project structure + +echo "Host setup completed successfully!" +echo "You can now start or rebuild your dev container." diff --git a/.devcontainer/project-setup.sh b/.devcontainer/project-setup.sh new file mode 100755 index 000000000..34fe59653 --- /dev/null +++ b/.devcontainer/project-setup.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# Project-specific setup script for graph +set -euo pipefail + +echo "Running project-specific setup for graph..." + +# Get the script directory and repository root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "Script directory: $SCRIPT_DIR" +echo "Repository root: $REPO_ROOT" + +# Set up local user directories with proper permissions +echo "Setting up local user directories..." + +# Ensure all user directories exist and have proper ownership +sudo mkdir -p /home/vscode/.cache /home/vscode/.config /home/vscode/.local/share /home/vscode/.local/bin +sudo chown -R vscode:vscode /home/vscode/.cache /home/vscode/.config /home/vscode/.local +sudo chmod -R 755 /home/vscode/.cache /home/vscode/.config /home/vscode/.local + +echo "User directories set up with proper permissions" + +# Install project dependencies +echo "Installing project dependencies..." +if [ -f "$REPO_ROOT/package.json" ]; then + echo "Running pnpm to install dependencies..." + cd "$REPO_ROOT" + # Note: With set -e, if pnpm fails, the script will exit + # This is desirable as we want to ensure dependencies are properly installed + pnpm install +else + echo "No package.json found in the root directory, skipping dependency installation" +fi + +# Add CONTAINER_BIN_PATH to PATH if it's set +if [ -n "${CONTAINER_BIN_PATH:-}" ]; then + echo "CONTAINER_BIN_PATH is set to: $CONTAINER_BIN_PATH" + echo "Adding CONTAINER_BIN_PATH to PATH..." + + # Add to current PATH + export PATH="$CONTAINER_BIN_PATH:$PATH" + + # Add to .bashrc if not already there + if ! grep -q "export PATH=\"\$CONTAINER_BIN_PATH:\$PATH\"" "$HOME/.bashrc"; then + echo "Adding CONTAINER_BIN_PATH to .bashrc..." + echo ' +# Add CONTAINER_BIN_PATH to PATH if set +if [ -n "${CONTAINER_BIN_PATH:-}" ]; then + export PATH="$CONTAINER_BIN_PATH:$PATH" +fi' >> "$HOME/.bashrc" + fi + + echo "CONTAINER_BIN_PATH added to PATH" +else + echo "CONTAINER_BIN_PATH is not set, skipping PATH modification" +fi + +# Source shell customizations if available in PATH +if command -v shell-customizations &> /dev/null; then + SHELL_CUSTOMIZATIONS_PATH=$(command -v shell-customizations) + echo "Found shell customizations in PATH at: ${SHELL_CUSTOMIZATIONS_PATH}" + echo "Sourcing shell customizations..." + source "${SHELL_CUSTOMIZATIONS_PATH}" + + # Add to .bashrc if not already there + if ! grep -q "source.*shell-customizations" "$HOME/.bashrc"; then + echo "Adding shell customizations to .bashrc..." + echo "source ${SHELL_CUSTOMIZATIONS_PATH}" >> "$HOME/.bashrc" + fi +else + echo "Shell customizations not found in PATH, skipping..." +fi + +# Set up Git SSH signing +if [ -f "$SCRIPT_DIR/setup-git-signing.sh" ]; then + "$SCRIPT_DIR/setup-git-signing.sh" +else + echo "WARNING: setup-git-signing.sh not found, skipping Git SSH signing setup" +fi + +echo "Project-specific setup completed" diff --git a/.devcontainer/sample-graph.env b/.devcontainer/sample-graph.env new file mode 100644 index 000000000..b6eab6144 --- /dev/null +++ b/.devcontainer/sample-graph.env @@ -0,0 +1,12 @@ +# Sample environment file for Graph Protocol contracts development +# Copy the Git settings below to your actual environment file at: +# /opt/configs/graphprotocol/contracts.env + +# Git settings for commit signing +# Add these settings if you want to enable Git commit signing +GIT_USER_NAME=Your Name +GIT_USER_EMAIL=your.email@example.com + +# Custom binary path +# Add this setting if you want to add a custom binary path to the PATH inside the container +# CONTAINER_BIN_PATH=/path/to/your/binaries diff --git a/.devcontainer/setup-git-signing.sh b/.devcontainer/setup-git-signing.sh new file mode 100755 index 000000000..78969dd62 --- /dev/null +++ b/.devcontainer/setup-git-signing.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# Automatically configure Git to use SSH signing with forwarded SSH keys +set -euo pipefail + +echo "Setting up Git SSH signing..." + +# Check if SSH agent forwarding is working +if ! ssh-add -l &>/dev/null; then + echo "ERROR: No SSH keys found in agent. SSH agent forwarding is not set up correctly." + echo "SSH signing will not work without SSH agent forwarding." + exit 1 +fi + +# Get the first SSH key from the agent +SSH_KEY=$(ssh-add -L | head -n 1) +if [ -z "$SSH_KEY" ]; then + echo "ERROR: No SSH keys found in agent. SSH signing will not work." + exit 1 +fi + +# Extract the key type and key content +KEY_TYPE=$(echo "$SSH_KEY" | awk '{print $1}') +KEY_CONTENT=$(echo "$SSH_KEY" | awk '{print $2}') + +# Check if Git user settings are available +if [[ -z "${GIT_USER_NAME:-}" || -z "${GIT_USER_EMAIL:-}" ]]; then + echo "WARNING: Git user settings (GIT_USER_NAME and/or GIT_USER_EMAIL) are not set." + echo "Git commit signing will not be configured." + echo "If you need Git commit signing, add these variables to your environment file." + exit 0 +fi + +# Set Git user name from environment variable +echo "Setting Git user.name: $GIT_USER_NAME" +git config --global user.name "$GIT_USER_NAME" + +# Set Git user email from environment variable +echo "Setting Git user.email: $GIT_USER_EMAIL" +git config --global user.email "$GIT_USER_EMAIL" + +# Create the .ssh directory if it doesn't exist +mkdir -p ~/.ssh +chmod 700 ~/.ssh + +# Create or update the allowed signers file +echo "Updating allowed signers file..." +ALLOWED_SIGNERS_FILE=~/.ssh/allowed_signers +SIGNER_LINE="$GIT_USER_EMAIL $KEY_TYPE $KEY_CONTENT" + +# Create the file if it doesn't exist +if [ ! -f "$ALLOWED_SIGNERS_FILE" ]; then + echo "$SIGNER_LINE" > "$ALLOWED_SIGNERS_FILE" + echo "Created new allowed signers file." +else + # Check if the key is already in the file + if ! grep -q "$KEY_CONTENT" "$ALLOWED_SIGNERS_FILE"; then + # Append the key if it's not already there + echo "$SIGNER_LINE" >> "$ALLOWED_SIGNERS_FILE" + echo "Added new key to allowed signers file." + else + echo "Key already exists in allowed signers file." + fi +fi + +chmod 600 "$ALLOWED_SIGNERS_FILE" + +# Configure Git to use SSH signing +echo "Configuring Git to use SSH signing..." +git config --global gpg.format ssh +git config --global user.signingkey "key::$KEY_TYPE $KEY_CONTENT" +git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers +git config --global commit.gpgsign true + +echo "Git SSH signing setup complete!" +echo "Your commits will now be automatically signed using your SSH key." +echo "Make sure this key is added to GitHub as a signing key in your account settings."