# Classic ASP Development Standards ## ShopDB Application **Version:** 1.2 **Last Updated:** 2025-12-12 **Status:** MANDATORY for all new development and modifications --- ## Table of Contents 1. [Security Standards](#security-standards) 2. [Database Access Standards](#database-access-standards) 3. [Input Validation Standards](#input-validation-standards) 4. [Output Encoding Standards](#output-encoding-standards) 5. [Error Handling Standards](#error-handling-standards) 6. [Code Structure Standards](#code-structure-standards) 7. [Naming Conventions](#naming-conventions) 8. [Documentation Standards](#documentation-standards) 9. [Performance Standards](#performance-standards) 10. [Testing Standards](#testing-standards) --- ## Security Standards ### Authentication & Authorization > **NOTE:** Authentication is not yet implemented. SAML integration is planned for a future release. The patterns below document the intended implementation. **MANDATORY (when implemented):** All pages MUST implement authentication checks. ```vbscript <% ' This will redirect to login if user is not authenticated Call RequireAuthentication() ' For administrative functions: Call RequireRole("Admin") %> ``` **Exception:** Only the following pages may skip authentication: - `login.asp` - `error.asp` - `404.asp` - API endpoints (use API key authentication instead) ### Session Management ```vbscript ' Standard session configuration (in sql.asp) Session.Timeout = APP_SESSION_TIMEOUT ' From config.asp ' After successful authentication: Session("authenticated") = True Session("userId") = userId Session("userName") = userName Session("userRole") = userRole Session("loginTime") = Now() Session.Abandon ' Only on explicit logout ``` ### Password Requirements - **Minimum Length:** 12 characters - **Complexity:** Must include uppercase, lowercase, number, special character - **Storage:** Never store plaintext passwords - **Transmission:** HTTPS only (enforce in IIS) ### Security Headers All pages MUST set appropriate security headers: ```vbscript Response.AddHeader "X-Content-Type-Options", "nosniff" Response.AddHeader "X-Frame-Options", "SAMEORIGIN" Response.AddHeader "X-XSS-Protection", "1; mode=block" Response.AddHeader "Content-Security-Policy", "default-src 'self'" ``` --- ## Database Access Standards ### Connection String **MANDATORY:** Use configuration file, NEVER hard-code credentials. ```vbscript <% ' In sql.asp - use config constants objConn.ConnectionString = GetConnectionString() objConn.Open %> ``` **Environment Toggle:** Set `USE_DSN` in config.asp: - `USE_DSN = False` - Development (direct ODBC driver connection) - `USE_DSN = True` - Production (DSN-based connection) ```vbscript ' config.asp controls connection method Const USE_DSN = False ' Set True for production Function GetConnectionString() If USE_DSN Then ' Production: DSN-based GetConnectionString = "DSN=" & DB_DSN & ";Uid=...;Pwd=...;Option=3;Pooling=True;Max Pool Size=100;" Else ' Development: Direct ODBC GetConnectionString = "Driver={" & DB_DRIVER & "};Server=...;..." End If End Function ``` ### Parameterized Queries **MANDATORY:** ALL database queries MUST use parameterization. ** NEVER DO THIS:** ```vbscript ' WRONG - SQL Injection vulnerable machineId = Request.QueryString("machineid") strSQL = "SELECT * FROM machines WHERE machineid = " & machineId Set rs = objConn.Execute(strSQL) ``` ** ALWAYS DO THIS:** ```vbscript ' CORRECT - Parameterized query machineId = GetSafeInteger("QS", "machineid", 0, 1, 999999) Set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = objConn cmd.CommandText = "SELECT * FROM machines WHERE machineid = ?" cmd.CommandType = 1 ' adCmdText Set param = cmd.CreateParameter("@machineid", 3, 1, , machineId) ' 3=adInteger, 1=adParamInput cmd.Parameters.Append param Set rs = cmd.Execute() ``` ### Resource Cleanup **MANDATORY:** Always clean up database resources. ```vbscript <% ' At the end of EVERY page: Call CleanupResources() %> ``` **Template:** ```vbscript <% On Error Resume Next ' Database operations here ' Before any Response.Redirect: Call CleanupResources() Response.Redirect("page.asp") Response.End ' At end of page: Call CleanupResources() On Error Goto 0 %> ``` ### Connection Pooling **MANDATORY:** Enable connection pooling in configuration. ```vbscript ' In config.asp GetConnectionString() function: connectionString = connectionString & "Pooling=True;Max Pool Size=100;" ``` --- ## Input Validation Standards ### Validation Library **MANDATORY:** Use validation functions for ALL user input. ```vbscript ``` ### Common Validation Patterns #### Integer IDs ```vbscript Dim machineId machineId = GetSafeInteger("QS", "machineid", 0, 1, 999999) If machineId = 0 Then Response.Redirect("error.asp?msg=INVALID_ID") Response.End End If ``` #### String Fields ```vbscript Dim serialNumber serialNumber = GetSafeString("FORM", "serialnumber", "", 7, 50, "^[A-Z0-9]+$") If serialNumber = "" Then Response.Redirect("adddevice.asp?error=INVALID_SERIAL") Response.End End If ``` #### IP Addresses ```vbscript Dim ipAddress ipAddress = Request.Form("ipaddress") If Not ValidateIPAddress(ipAddress) Then Response.Redirect("error.asp?msg=INVALID_IP") Response.End End If ``` #### Email Addresses ```vbscript Dim email email = Request.Form("email") If Not ValidateEmail(email) Then Response.Redirect("error.asp?msg=INVALID_EMAIL") Response.End End If ``` ### Whitelist Validation **PREFERRED:** Use whitelist validation whenever possible. ```vbscript ' Example: Only allow specific status values Dim status status = Request.Form("status") If status <> "active" And status <> "inactive" And status <> "pending" Then Response.Redirect("error.asp?msg=INVALID_STATUS") Response.End End If ``` ### Client-Side Validation **REQUIRED:** Implement client-side validation for user experience. **CRITICAL:** Client-side validation does NOT replace server-side validation. ```html
``` --- ## Output Encoding Standards ### HTML Output **MANDATORY:** ALL user-controlled output MUST be HTML-encoded. ** NEVER DO THIS:** ```vbscript
<%=rs("machinename")%>

<%Response.Write(rs("description"))%>

``` ** ALWAYS DO THIS:** ```vbscript
<%=Server.HTMLEncode(rs("machinename"))%>

<%Response.Write(Server.HTMLEncode(rs("description")))%>

``` ### JavaScript Context **MANDATORY:** Use JavaScript encoding for data in JavaScript. ```vbscript ``` ```vbscript ' Helper function in includes/encoding.asp Function JavaScriptEncode(str) Dim result result = Replace(str, "\", "\\") result = Replace(result, "'", "\'") result = Replace(result, """", "\""") result = Replace(result, vbCrLf, "\n") result = Replace(result, vbCr, "\n") result = Replace(result, vbLf, "\n") JavaScriptEncode = result End Function ``` ### URL Parameters **MANDATORY:** Use URLEncode for URL parameters. ```vbscript ">Link ``` ### JSON Output **MANDATORY:** Properly escape JSON output. ```vbscript <% Response.ContentType = "application/json" Response.Write(CreateJSONFromRecordset(rs)) %> ``` --- ## Error Handling Standards ### Standard Error Handler **MANDATORY:** Include error handler in ALL pages. ```vbscript <% Call InitializeErrorHandling("pagename.asp") ' Page logic here Call CheckForErrors() ' After each critical operation Call CleanupResources() %> ``` ### Error Logging **MANDATORY:** Log all errors to server-side log file. ```vbscript ' In error_handler.asp Call LogError(pageName, Err.Number, Err.Description, Request.ServerVariables("REMOTE_ADDR")) ``` **Log Format:** ``` 2025-10-10 14:35:22 | displaymachine.asp | -2147467259 | Syntax error in SQL | 192.168.122.1 ``` ### User-Facing Error Messages **MANDATORY:** NEVER expose technical details to users. ** WRONG:** ```vbscript Response.Write("Error: " & Err.Description) ``` ** CORRECT:** ```vbscript Response.Redirect("error.asp?code=DATABASE_ERROR") ``` ### Error Codes Standard error codes for user messaging: - `INVALID_INPUT` - User input validation failed - `NOT_FOUND` - Record not found - `UNAUTHORIZED` - User lacks permission - `DATABASE_ERROR` - Database operation failed - `GENERAL_ERROR` - Catch-all for unexpected errors --- ## Code Structure Standards ### File Header **MANDATORY:** Every ASP file must have a header comment block. ```vbscript <% '============================================================================= ' FILE: displaymachine.asp ' PURPOSE: Display detailed information for a single machine ' ' PARAMETERS: ' machineid (QueryString, Required) - Integer ID of machine to display ' ' DEPENDENCIES: ' - includes/config.asp - Application configuration ' - includes/sql.asp - Database connection ' - includes/validation.asp - Input validation functions ' - includes/auth_check.asp - Authentication verification ' ' DATABASE TABLES: ' - machines (primary) ' - machinetypes, models, vendors, businessunits ' - printers (LEFT JOIN - may be NULL) ' - communications (LEFT JOIN - may be NULL) ' ' SECURITY: ' - Requires authentication ' - No special role required (read-only) ' - Uses parameterized queries ' ' AUTHOR: [Your Name] ' CREATED: 2025-10-10 ' MODIFIED: 2025-10-10 - Initial version ' '============================================================================= %> ``` ### Standard Page Template ```vbscript <%@ Language=VBScript %> <% Option Explicit ' MANDATORY - Forces variable declaration %> Page Title <% '----------------------------------------------------------------------------- ' AUTHENTICATION '----------------------------------------------------------------------------- Call RequireAuthentication() '----------------------------------------------------------------------------- ' INITIALIZATION '----------------------------------------------------------------------------- Call InitializeErrorHandling("pagename.asp") ' Get and validate parameters Dim paramId paramId = GetSafeInteger("QS", "id", 0, 1, 999999) If paramId = 0 Then Call CleanupResources() Response.Redirect("error.asp?msg=INVALID_ID") Response.End End If ' Get theme preference Dim theme theme = Request.Cookies("theme") If theme = "" Then theme = "bg-theme1" '----------------------------------------------------------------------------- ' DATABASE OPERATIONS '----------------------------------------------------------------------------- Dim strSQL, objRS strSQL = "SELECT * FROM tablename WHERE id = ?" Set objRS = ExecuteParameterizedQuery(objConn, strSQL, Array(paramId)) Call CheckForErrors() If objRS.EOF Then Call CleanupResources() Response.Redirect("error.asp?msg=NOT_FOUND") Response.End End If %>
<%=Server.HTMLEncode(objRS("name"))%>
<% '----------------------------------------------------------------------------- ' CLEANUP '----------------------------------------------------------------------------- Call CleanupResources() %> ``` ### Form Processing Template ```vbscript <%@ Language=VBScript %> <% Option Explicit %> <% '----------------------------------------------------------------------------- ' AUTHENTICATION '----------------------------------------------------------------------------- Call RequireAuthentication() Call RequireRole("Editor") ' If write operation requires special role '----------------------------------------------------------------------------- ' INITIALIZATION '----------------------------------------------------------------------------- Call InitializeErrorHandling("savepage.asp") '----------------------------------------------------------------------------- ' VALIDATE INPUT '----------------------------------------------------------------------------- Dim recordId, fieldValue1, fieldValue2 recordId = GetSafeInteger("FORM", "id", 0, 0, 999999) fieldValue1 = GetSafeString("FORM", "field1", "", 1, 100, "^[A-Za-z0-9 ]+$") fieldValue2 = GetSafeString("FORM", "field2", "", 0, 200, "") If fieldValue1 = "" Then Call CleanupResources() Response.Redirect("editpage.asp?id=" & recordId & "&error=REQUIRED_FIELD") Response.End End If '----------------------------------------------------------------------------- ' DATABASE OPERATION '----------------------------------------------------------------------------- Dim strSQL If recordId > 0 Then ' Update existing record strSQL = "UPDATE tablename SET field1 = ?, field2 = ?, lastupdated = NOW() WHERE id = ?" Call ExecuteParameterizedUpdate(objConn, strSQL, Array(fieldValue1, fieldValue2, recordId)) Else ' Insert new record strSQL = "INSERT INTO tablename (field1, field2, created) VALUES (?, ?, NOW())" Call ExecuteParameterizedInsert(objConn, strSQL, Array(fieldValue1, fieldValue2)) recordId = CLng(objConn.Execute("SELECT LAST_INSERT_ID() AS id")(0)) End If Call CheckForErrors() '----------------------------------------------------------------------------- ' CLEANUP AND REDIRECT '----------------------------------------------------------------------------- Call CleanupResources() Response.Redirect("displaypage.asp?id=" & recordId & "&success=1") %> ``` --- ## Naming Conventions ### Variables **Style:** camelCase ```vbscript ' IDs - use "Id" suffix Dim machineId, printerId, userId ' Strings - descriptive names Dim serialNumber, ipAddress, userName, description ' Booleans - use "is" or "has" prefix Dim isActive, hasPermission, isValid ' Database objects - use obj prefix Dim objConn, objCmd, objRS ' SQL queries - use str prefix Dim strSQL, strSQL2 ' Counters/indexes - single letter or descriptive Dim i, j, rowCount, itemIndex ``` ### Constants **Style:** UPPER_CASE_WITH_UNDERSCORES ```vbscript Const DB_SERVER = "192.168.122.1" Const MAX_FILE_SIZE = 10485760 Const SESSION_TIMEOUT = 30 Const DEFAULT_PAGE_SIZE = 50 ``` ### Functions **Style:** PascalCase, verb-noun format ```vbscript Function GetMachineById(machineId) Function ValidateIPAddress(ipAddress) Function RenderVendorDropdown(selectedId, filterType) Function CreateJSONResponse(success, message, data) Function CalculateTotalCost(items) ``` ### Subroutines **Style:** PascalCase, verb-noun format ```vbscript Sub InitializeErrorHandling(pageName) Sub CleanupResources() Sub RequireAuthentication() Sub LogError(source, errorNum, errorDesc) ``` ### Files **Display Pages (single record):** display[noun-singular].asp - `displaymachine.asp` - `displayprinter.asp` - `displaypc.asp` **List Pages (multiple records):** display[noun-plural].asp - `displaymachines.asp` - `displayprinters.asp` - `displaypcs.asp` **Edit Pages:** edit[noun-singular].asp - `editmachine.asp` - `editprinter.asp` - `editpc.asp` **Add Pages:** add[noun-singular].asp - `addmachine.asp` - `addprinter.asp` - `addpc.asp` **Form Processors:** [verb][noun].asp - `savemachine.asp` - `updatemachine.asp` - `deletemachine.asp` **Include Files:** descriptive lowercase - `sql.asp` - `config.asp` - `validation.asp` - `error_handler.asp` - `auth_check.asp` ### Database Tables **Style:** lowercase, plural nouns ```sql machines -- Unified table: Equipment, PCs, Network Devices printers communications -- Network interfaces (IP/MAC) machinetypes vendors models ``` ### Database Columns **Style:** lowercase, descriptive ```sql machineid machinenumber serialnumber ipaddress isactive createdate lastupdated ``` ### Column Naming Gotchas **IMPORTANT:** Be aware of these non-obvious column names: | Expected | Actual | Table | |----------|--------|-------| | `ipaddress` | `address` | communications | | `gateway` | `defaultgateway` | communications | | `communicationid` | `comid` | communications | | `notes` | `machinenotes` | machines | | `pcid` | `machineid` | machines (PCs are in unified table) | | `pc_comm_config` | `commconfig` | (table name) | | `pc_dnc_config` | `dncconfig` | (table name) | **PC Identification:** PCs are in the `machines` table, identified by: - `pctypeid IS NOT NULL` - `machinetypeid = 33` (generic PC type) > **Note:** Redundant PC machinetypes (34-46) were removed. All PCs now use machinetypeid=33 with pctypeid for categorization (Standard, Engineer, Shopfloor, CMM, etc.) --- ## Documentation Standards ### Inline Comments **REQUIRED:** Comment complex logic and business rules. ```vbscript '----------------------------------------------------------------------------- ' Search Logic: ' 1. Check if input matches machine number (exact) or alias (partial) ' 2. If starts with "csf" and length=5, search printer CSF names ' 3. If 7 alphanumeric chars, treat as PC serial number ' 4. If valid IP, find containing subnet ' 5. If 9 digits, treat as SSO employee number ' 6. If starts with ticket prefix, redirect to ServiceNow ' 7. Otherwise, full-text search knowledge base '----------------------------------------------------------------------------- ``` ### SQL Query Comments **RECOMMENDED:** Document complex queries. ```vbscript '----------------------------------------------------------------------------- ' QUERY: Get machine with all related data ' ' Retrieves: ' - Machine details (machines table) ' - Type and function account (for billing) ' - Model and vendor information ' - Business unit assignment ' - Associated printer (LEFT JOIN - may be NULL) ' - Associated PC (LEFT JOIN - may be NULL) ' ' LEFT JOINs used because not all machines have printers/PCs. '----------------------------------------------------------------------------- strSQL = "SELECT m.*, mt.machinetype, mdl.modelnumber, " & _ " v.vendor, bu.businessunit, " & _ " p.ipaddress AS printerip " & _ "FROM machines m " & _ "INNER JOIN machinetypes mt ON m.machinetypeid = mt.machinetypeid " & _ "LEFT JOIN printers p ON m.printerid = p.printerid " & _ "WHERE m.machineid = ?" ``` ### Function Documentation **MANDATORY:** Document all functions and subroutines. ```vbscript '----------------------------------------------------------------------------- ' FUNCTION: ValidateIPAddress ' PURPOSE: Validates that a string is a valid IPv4 address ' ' PARAMETERS: ' ipAddress (String) - The IP address to validate ' ' RETURNS: ' Boolean - True if valid IPv4 address, False otherwise ' ' EXAMPLES: ' ValidateIPAddress("192.168.1.1") -> True ' ValidateIPAddress("192.168.1.256") -> False ' ValidateIPAddress("not an ip") -> False ' ' VALIDATION: ' - Must match pattern: XXX.XXX.XXX.XXX ' - Each octet must be 0-255 ' - No leading zeros allowed '----------------------------------------------------------------------------- Function ValidateIPAddress(ipAddress) Dim objRegEx, pattern Set objRegEx = New RegExp pattern = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" objRegEx.Pattern = pattern ValidateIPAddress = objRegEx.Test(ipAddress) End Function ``` ### TODO Comments **ENCOURAGED:** Use standardized TODO format. ```vbscript ' TODO: SECURITY - Add authentication check (HIGH PRIORITY) ' TODO: PERFORMANCE - Cache this query result ' TODO: VALIDATION - Add email format validation ' TODO: REFACTOR - Extract to reusable function ' TODO: BUG - Handle null value edge case ``` --- ## Performance Standards ### Database Query Optimization **REQUIRED:** Follow these query optimization practices. #### Use Specific Columns ```vbscript ' BAD strSQL = "SELECT * FROM machines" ' GOOD strSQL = "SELECT machineid, machinenumber, machinetype FROM machines" ``` #### Use Appropriate JOINs ```vbscript ' Use INNER JOIN when relationship is required ' Use LEFT JOIN when relationship is optional ' Avoid RIGHT JOIN (use LEFT JOIN instead for clarity) ``` #### Limit Result Sets ```vbscript ' For list views, always implement paging strSQL = "SELECT * FROM machines WHERE isactive = 1 " & _ "ORDER BY machinenumber " & _ "LIMIT " & pageSize & " OFFSET " & offset ``` ### Caching Strategy **REQUIRED:** Cache reference data at application scope. ```vbscript ' In global.asa Application_OnStart Sub Application_OnStart ' Cache rarely-changing reference data Call LoadVendorCache() Call LoadModelCache() Call LoadMachineTypeCache() End Sub ' In data_cache.asp Function GetCachedVendors() If IsEmpty(Application("CachedVendors")) Or _ DateDiff("s", Application("VendorCacheTime"), Now()) > CACHE_DURATION Then Call LoadVendorCache() End If GetCachedVendors = Application("CachedVendors") End Function ``` **Cache Invalidation:** - Time-based: 5-30 minutes for reference data - Event-based: Invalidate when data is modified - Manual: Provide admin function to clear cache ### Response Buffering **REQUIRED:** Enable response buffering. ```vbscript <% Response.Buffer = True %> ``` **Benefits:** - Allows headers to be set after content generation - Enables proper error handling with redirects - Improves performance by sending larger chunks ### Minimize Database Roundtrips **PREFERRED:** Consolidate queries when possible. ```vbscript ' BAD - 4 separate queries Set rsVendors = objConn.Execute("SELECT * FROM vendors") Set rsModels = objConn.Execute("SELECT * FROM models") Set rsTypes = objConn.Execute("SELECT * FROM machinetypes") Set rsUnits = objConn.Execute("SELECT * FROM businessunits") ' BETTER - Use cached data Response.Write(RenderCachedVendorDropdown()) Response.Write(RenderCachedModelDropdown()) Response.Write(RenderCachedTypeDropdown()) Response.Write(RenderCachedUnitDropdown()) ``` --- ## Testing Standards ### Automated Form Testing **REQUIRED:** Run the comprehensive test suite after making changes to ASP pages. ```bash ./tests/test_forms.sh ``` This script tests 41 endpoints including: - Page load tests (dashboards, list views, maps) - Add form page loads - Form submissions (notifications, equipment, printers, subnets, applications, KB, vendors, models, network devices) - API endpoints Test data uses `AUTOTEST_` prefix for easy cleanup. See `tests/cleanup_test_data.sql`. ### API Endpoint Testing **REQUIRED:** Test API endpoints used by PowerShell scripts after changes to api.asp. ```bash # Health check curl -s "http://192.168.122.151:8080/api.asp?action=getDashboardData" # Get shopfloor PCs curl -s "http://192.168.122.151:8080/api.asp?action=getShopfloorPCs" # Simulate PowerShell PC data collection curl -s -X POST "http://192.168.122.151:8080/api.asp" \ -d "action=updateCompleteAsset" \ -d "hostname=TESTPC01" \ -d "serialNumber=TEST123" \ -d "manufacturer=Dell Inc." \ -d "model=OptiPlex 7080" \ -d "osVersion=Microsoft Windows 11 Pro" \ -d "pcType=Standard" # Get recorded IP (POST method) curl -s -X POST "http://192.168.122.151:8080/api.asp" \ -d "action=getRecordedIP" \ -d "hostname=TESTPC01" ``` **Key API Endpoints:** | Action | Method | Purpose | |--------|--------|---------| | getDashboardData | GET | Health check | | getShopfloorPCs | GET | List shopfloor PCs | | updateCompleteAsset | POST | PC data collection (main PowerShell endpoint) | | getRecordedIP | POST | Get recorded IP for hostname | | updatePrinterMapping | POST | Link printer to PC | | updateInstalledApps | POST | Record installed applications | ### Unit Testing **REQUIRED:** Test all validation functions. Create test file: `tests/test_validation.asp` ```vbscript <% Sub TestValidateIPAddress() If ValidateIPAddress("192.168.1.1") Then Response.Write("PASS: Valid IP accepted
") Else Response.Write("FAIL: Valid IP rejected
") End If If Not ValidateIPAddress("999.999.999.999") Then Response.Write("PASS: Invalid IP rejected
") Else Response.Write("FAIL: Invalid IP accepted
") End If End Sub Call TestValidateIPAddress() %> ``` ### Integration Testing **RECOMMENDED:** Test critical user flows. **Test Cases:** 1. User login flow 2. Machine creation flow 3. Machine update flow 4. Search functionality 5. Report generation ### Security Testing **REQUIRED:** Test for common vulnerabilities. **Test Checklist:** - [ ] SQL injection attempts on all input fields - [ ] XSS payloads in all text fields - [ ] Access control bypass attempts - [ ] Session hijacking scenarios - [ ] CSRF token validation ### Load Testing **RECOMMENDED:** Test under expected load. **Metrics to Monitor:** - Response time per page - Database connection pool usage - Memory consumption - Concurrent user capacity --- ## Code Review Checklist Before committing code, verify: ### Security - [ ] Authentication check present - [ ] All queries use parameterization - [ ] All output is HTML-encoded - [ ] Input validation implemented - [ ] No credentials in code ### Error Handling - [ ] Error handler included - [ ] Resources cleaned up on all paths - [ ] No technical details exposed to users - [ ] Errors logged to server ### Code Quality - [ ] File header present - [ ] Complex logic commented - [ ] Naming conventions followed - [ ] No code duplication - [ ] No commented-out debug code ### Performance - [ ] Queries optimized - [ ] Appropriate caching used - [ ] Resources properly closed - [ ] Result sets limited/paged ### Testing - [ ] Manually tested happy path - [ ] Tested error conditions - [ ] Tested with invalid input - [ ] Cross-browser tested (if UI changes) --- ## Configuration Management ### Environment-Specific Configurations **Structure:** ``` /includes/ config.asp.example (Template with placeholder credentials - tracked in git) config.asp (Actual credentials - gitignored, never commit) ``` **Deployment Process:** 1. Copy `config.asp.example` to `config.asp` 2. Fill in actual credentials 3. Set `USE_DSN = True` for production, `False` for development 4. `config.asp` is gitignored - never committed to source control **Configuration includes:** - ShopDB credentials (with DSN/direct ODBC toggle) - Employee database credentials (with DSN/direct ODBC toggle) - Zabbix API URL and token - Application settings (session timeout, page size, cache duration) - Business logic constants (serial number length, CSF prefix, etc.) ### Secrets Management **MANDATORY:** Store sensitive credentials in `secrets.md` (gitignored). **Contents:** - Zabbix API URL and token - Gitea API URL and token - Database credentials (per environment) **NEVER commit:** - API tokens - Database passwords - Authentication credentials ### Configuration Template See `includes/config.asp.example` for the full template. Key sections: ```vbscript <% '============================================================================= ' Database Configuration - ShopDB '============================================================================= ' Toggle between DSN (production) and direct ODBC (development) Const USE_DSN = False ' Set True for production ' DSN configuration (production) Const DB_DSN = "shopdb" Const DB_DSN_USER = "YOUR_DB_USER" Const DB_DSN_PASSWORD = "YOUR_DB_PASSWORD" ' Direct ODBC configuration (development) Const DB_DRIVER = "MySQL ODBC 9.4 Unicode Driver" Const DB_SERVER = "192.168.122.1" Const DB_PORT = "3306" Const DB_NAME = "shopdb" Const DB_USER = "YOUR_DB_USER" Const DB_PASSWORD = "YOUR_DB_PASSWORD" '============================================================================= ' Database Configuration - Employee Database '============================================================================= Const USE_EMP_DSN = True ' Usually DSN-based Const EMP_DB_DSN = "wjf_employees" Const EMP_DB_DSN_USER = "YOUR_EMP_USER" Const EMP_DB_DSN_PASSWORD = "YOUR_EMP_PASSWORD" '============================================================================= ' External Services '============================================================================= Const ZABBIX_URL = "http://your-zabbix-server/api_jsonrpc.php" Const ZABBIX_API_TOKEN = "YOUR_ZABBIX_API_TOKEN" '============================================================================= ' Helper Functions '============================================================================= Function GetConnectionString() If USE_DSN Then GetConnectionString = "DSN=" & DB_DSN & ";Uid=" & DB_DSN_USER & _ ";Pwd=" & DB_DSN_PASSWORD & ";Option=3;Pooling=True;Max Pool Size=100;" Else GetConnectionString = "Driver={" & DB_DRIVER & "};Server=" & DB_SERVER & _ ";Port=" & DB_PORT & ";Database=" & DB_NAME & _ ";User=" & DB_USER & ";Password=" & DB_PASSWORD & _ ";Option=3;Pooling=True;Max Pool Size=100;" End If End Function %> ``` --- ## Migration Guide ### Updating Existing Files to Meet Standards **Priority Order:** 1. Add authentication check 2. Fix SQL injection vulnerabilities 3. Add HTML encoding to output 4. Add error handling 5. Add file header documentation 6. Refactor for code quality ### Example Migration **Before (Non-Compliant):** ```vbscript Machine <% machineid = Request.QueryString("machineid") strSQL = "SELECT * FROM machines WHERE machineid = " & machineid set rs = objconn.Execute(strSQL) %>

<%=rs("machinename")%>

``` **After (Standards-Compliant):** ```vbscript <%@ Language=VBScript %> <% Option Explicit %> Machine Details <% '----------------------------------------------------------------------------- ' FILE: displaymachine.asp ' PURPOSE: Display machine details '----------------------------------------------------------------------------- Call RequireAuthentication() Call InitializeErrorHandling("displaymachine.asp") Dim machineId, strSQL, objRS machineId = GetSafeInteger("QS", "machineid", 0, 1, 999999) If machineId = 0 Then Call CleanupResources() Response.Redirect("error.asp?msg=INVALID_ID") Response.End End If strSQL = "SELECT * FROM machines WHERE machineid = ?" Set objRS = ExecuteParameterizedQuery(objConn, strSQL, Array(machineId)) Call CheckForErrors() If objRS.EOF Then Call CleanupResources() Response.Redirect("error.asp?msg=NOT_FOUND") Response.End End If %>

<%=Server.HTMLEncode(objRS("machinename"))%>

<% Call CleanupResources() %> ``` --- ## Enforcement ### Code Review Process **MANDATORY:** All code changes must be reviewed before deployment. **Reviewer Checklist:** 1. Standards compliance verified 2. Security vulnerabilities checked 3. Performance impact assessed 4. Documentation adequate 5. Tests passed ### Automated Checks **RECOMMENDED:** Implement automated scanning where possible. **Tools:** - SQL injection scanner - XSS vulnerability scanner - Code style checker - Dead code detector ### Training **REQUIRED:** All developers must: 1. Read this standards document 2. Complete security training 3. Review example compliant code 4. Pass knowledge assessment --- ## Version History | Version | Date | Changes | Author | |---------|------|---------|--------| | 1.0 | 2025-10-10 | Initial standards document created from audit findings | Claude | | 1.1 | 2025-12-11 | Updated for Phase 2 schema (unified machines table), added test script reference, secrets management, column naming gotchas | Claude | | 1.2 | 2025-12-12 | Added DSN toggle documentation, API endpoint testing section, updated PC identification (machinetypeid=33 only), added comid column gotcha, noted auth not yet implemented, updated config file structure | Claude | --- ## Questions & Support For questions about these standards: 1. Review the examples in this document 2. Check existing compliant code for patterns 3. Consult with team lead 4. Document unclear areas for future clarification --- **REMEMBER:** These standards exist to protect our application and data. Following them is not optional—it's a requirement for all development work.